From 12bf504d6f8408144c69cb6290931ff75f63fb2f Mon Sep 17 00:00:00 2001 From: BFlat Date: Mon, 6 Oct 2025 14:57:33 +0700 Subject: [PATCH] =?UTF-8?q?faq=20and=20tutorials=20update=20to=20use=20mar?= =?UTF-8?q?kdown,=20footer=20updates,=20landing=20vid=E2=80=A6=20(#868)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …eo layout shift fix --- frontend/apps/artcraft-website/_redirects | 4 + .../apps/artcraft-website/src/app/app.tsx | 6 + .../src/components/footer/footer.tsx | 71 ++++++++- .../src/components/navbar/navbar.tsx | 67 ++------ .../artcraft-website/src/components/seo.tsx | 41 +++++ .../src/pages/faq/article.tsx | 115 ++++++++++++++ .../src/pages/faq/content/2d-canvas.md | 26 +++ .../src/pages/faq/content/3d-editor.md | 27 ++++ .../ai-image-generation-on-artcraft.md | 36 +++++ .../src/pages/faq/content/edit-image.md | 26 +++ ...nerate-ai-photos-and-videos-of-yourself.md | 31 ++++ .../src/pages/faq/content/image-to-video.md | 27 ++++ .../src/pages/faq/content/models-supported.md | 34 ++++ .../src/pages/faq/content/text-to-image.md | 28 ++++ .../artcraft-website/src/pages/faq/index.tsx | 74 +++++++++ .../apps/artcraft-website/src/pages/index.ts | 3 + .../src/pages/landing2/landing2.tsx | 8 +- .../src/pages/tutorials/article.tsx | 137 ++++++++++++++++ .../tutorials/content/2d-editor-basics.md | 11 ++ .../tutorials/content/3d-editor-basics.md | 12 ++ .../content/turn-images-into-objects.md | 12 ++ .../src/pages/tutorials/md-index.tsx | 56 +++++++ .../src/pages/tutorials/tutorials.tsx | 150 +++++++++--------- .../artcraft-website/src/utils/markdown.ts | 126 +++++++++++++++ 24 files changed, 995 insertions(+), 133 deletions(-) create mode 100644 frontend/apps/artcraft-website/src/components/seo.tsx create mode 100644 frontend/apps/artcraft-website/src/pages/faq/article.tsx create mode 100644 frontend/apps/artcraft-website/src/pages/faq/content/2d-canvas.md create mode 100644 frontend/apps/artcraft-website/src/pages/faq/content/3d-editor.md create mode 100644 frontend/apps/artcraft-website/src/pages/faq/content/ai-image-generation-on-artcraft.md create mode 100644 frontend/apps/artcraft-website/src/pages/faq/content/edit-image.md create mode 100644 frontend/apps/artcraft-website/src/pages/faq/content/generate-ai-photos-and-videos-of-yourself.md create mode 100644 frontend/apps/artcraft-website/src/pages/faq/content/image-to-video.md create mode 100644 frontend/apps/artcraft-website/src/pages/faq/content/models-supported.md create mode 100644 frontend/apps/artcraft-website/src/pages/faq/content/text-to-image.md create mode 100644 frontend/apps/artcraft-website/src/pages/faq/index.tsx create mode 100644 frontend/apps/artcraft-website/src/pages/tutorials/article.tsx create mode 100644 frontend/apps/artcraft-website/src/pages/tutorials/content/2d-editor-basics.md create mode 100644 frontend/apps/artcraft-website/src/pages/tutorials/content/3d-editor-basics.md create mode 100644 frontend/apps/artcraft-website/src/pages/tutorials/content/turn-images-into-objects.md create mode 100644 frontend/apps/artcraft-website/src/pages/tutorials/md-index.tsx create mode 100644 frontend/apps/artcraft-website/src/utils/markdown.ts diff --git a/frontend/apps/artcraft-website/_redirects b/frontend/apps/artcraft-website/_redirects index f6038a8eb9..73a425d6d1 100644 --- a/frontend/apps/artcraft-website/_redirects +++ b/frontend/apps/artcraft-website/_redirects @@ -1,4 +1,8 @@ /tutorials /index.html 200 /tutorials/ /index.html 200 +/faq /index.html 200 +/faq/ /index.html 200 +/faq/* /index.html 200 + diff --git a/frontend/apps/artcraft-website/src/app/app.tsx b/frontend/apps/artcraft-website/src/app/app.tsx index 4523d157f6..82a72e1789 100644 --- a/frontend/apps/artcraft-website/src/app/app.tsx +++ b/frontend/apps/artcraft-website/src/app/app.tsx @@ -3,6 +3,9 @@ import Download from "../pages/download"; import Navbar from "../components/navbar"; import Landing2 from "../pages/landing2"; import TutorialsPage from "../pages/tutorials"; +import TutorialsArticle from "../pages/tutorials/article"; +import FaqIndex from "../pages/faq/index"; +import FaqArticle from "../pages/faq/article"; export function App() { return ( @@ -13,6 +16,9 @@ export function App() { } /> } /> } /> + } /> + } /> + } /> ); diff --git a/frontend/apps/artcraft-website/src/components/footer/footer.tsx b/frontend/apps/artcraft-website/src/components/footer/footer.tsx index 121734aeaf..49e042a268 100644 --- a/frontend/apps/artcraft-website/src/components/footer/footer.tsx +++ b/frontend/apps/artcraft-website/src/components/footer/footer.tsx @@ -7,10 +7,24 @@ import { faGithubAlt, } from "@fortawesome/free-brands-svg-icons"; import { SOCIAL_LINKS } from "../../config/links"; +import { parseFrontmatter, pathToFilename } from "../../utils/markdown"; + +const faqFiles = import.meta.glob("../../pages/faq/content/*.md", { + query: "?raw", + import: "default", + eager: true, +}); +const tutorialFiles = import.meta.glob("../../pages/tutorials/content/*.md", { + query: "?raw", + import: "default", + eager: true, +}); const navigation = { main: [ { name: "Home", href: "/" }, + { name: "Tutorials", href: "/tutorials" }, + { name: "FAQ", href: "/faq" }, { name: "Download", href: "/download" }, ], social: [ @@ -62,8 +76,8 @@ export default function Example() { ))} */} -
-
+
+
{navigation.social.map((item) => ( ))}
-

+

+ +
+
Tutorials
+ + All Tutorials + + {Object.entries(tutorialFiles).map(([path, raw]) => { + const { frontmatter } = parseFrontmatter(raw as string); + const slug = pathToFilename(path); + if (frontmatter.isPublished === "false") return null; + return ( + + {frontmatter.title || slug} + + ); + })} +
+
+
FAQ
+ + All FAQs + + {Object.entries(faqFiles).map(([path, raw]) => { + const { frontmatter } = parseFrontmatter(raw as string); + const slug = pathToFilename(path); + if (frontmatter.isPublished === "false") return null; + const title = (frontmatter.title || slug) as string; + const truncated = + title.length > 36 ? title.slice(0, 33) + "…" : title; + return ( + + {truncated} + + ); + })} +
+
+

© 2025 ArtCraft. All rights reserved.

diff --git a/frontend/apps/artcraft-website/src/components/navbar/navbar.tsx b/frontend/apps/artcraft-website/src/components/navbar/navbar.tsx index c3ada3e80c..e12e024ec4 100644 --- a/frontend/apps/artcraft-website/src/components/navbar/navbar.tsx +++ b/frontend/apps/artcraft-website/src/components/navbar/navbar.tsx @@ -1,37 +1,19 @@ import { Disclosure } from "@headlessui/react"; import { twMerge } from "tailwind-merge"; -import { useEffect, useRef, useState } from "react"; -import { useLocation } from "react-router-dom"; +import { useEffect, useState } from "react"; +import { Link, useLocation } from "react-router-dom"; import { DiscordButton } from "../discord-button"; const NAV_ITEMS = [ { name: "Home", href: "/" }, { name: "Tutorials", href: "/tutorials" }, + { name: "FAQ", href: "/faq" }, ]; export default function Navbar() { const [scrolled, setScrolled] = useState(false); const location = useLocation(); - const [underlineAnim, setUnderlineAnim] = useState< - Record - >({}); - const outTimersRef = useRef>({}); - - const handleEnter = (href: string) => { - if (outTimersRef.current[href] !== undefined) { - window.clearTimeout(outTimersRef.current[href]); - delete outTimersRef.current[href]; - } - setUnderlineAnim((prev) => ({ ...prev, [href]: "in" })); - }; - - const handleLeave = (href: string) => { - setUnderlineAnim((prev) => ({ ...prev, [href]: "out" })); - outTimersRef.current[href] = window.setTimeout(() => { - setUnderlineAnim((prev) => ({ ...prev, [href]: null })); - delete outTimersRef.current[href]; - }, 260); - }; + // Underline hover handled purely via CSS useEffect(() => { const handleScroll = () => { @@ -56,31 +38,29 @@ export default function Navbar() {
- + ArtCraft - +
{NAV_ITEMS.map((item) => { const isCurrent = location.pathname === item.href; - const anim = underlineAnim[item.href] ?? null; return ( - !isCurrent && handleEnter(item.href)} - onMouseLeave={() => !isCurrent && handleLeave(item.href)} > {item.name} - + ); })}
@@ -154,25 +128,16 @@ export default function Navbar() { transform-origin: left center; transform: scaleX(0) translateX(0); opacity: 0; + transition: transform 220ms ease, opacity 220ms ease; + } + .nav-link:hover .link-underline { + transform: scaleX(1) translateX(0); + opacity: 1; } .visible-line { transform: scaleX(1) translateX(0); opacity: 1; } - .hidden-line { - transform: scaleX(0) translateX(0); - opacity: 0; - } - @keyframes underline-in { - 0% { transform: scaleX(0) translateX(0); opacity: 0.8; } - 100% { transform: scaleX(1) translateX(0); opacity: 1; } - } - @keyframes underline-out { - 0% { transform: scaleX(1) translateX(0); opacity: 1; } - 100% { transform: scaleX(1) translateX(100%); opacity: 0; } - } - .animate-in { animation: underline-in 220ms ease-out forwards; } - .animate-out { animation: underline-out 220ms ease-in forwards; } `} ); diff --git a/frontend/apps/artcraft-website/src/components/seo.tsx b/frontend/apps/artcraft-website/src/components/seo.tsx new file mode 100644 index 0000000000..52ee52dd35 --- /dev/null +++ b/frontend/apps/artcraft-website/src/components/seo.tsx @@ -0,0 +1,41 @@ +import { useEffect } from "react"; + +type SeoProps = { + title: string; + description?: string; + jsonLd?: object | object[]; +}; + +const Seo = ({ title, description, jsonLd }: SeoProps) => { + useEffect(() => { + document.title = title; + + if (description) { + let meta = document.querySelector( + 'meta[name="description"]' + ) as HTMLMetaElement | null; + if (!meta) { + meta = document.createElement("meta"); + meta.setAttribute("name", "description"); + document.head.appendChild(meta); + } + meta.setAttribute("content", description); + } + + let script: HTMLScriptElement | null = null; + if (jsonLd) { + script = document.createElement("script"); + script.type = "application/ld+json"; + script.text = JSON.stringify(jsonLd); + document.head.appendChild(script); + } + + return () => { + if (script && script.parentNode) script.parentNode.removeChild(script); + }; + }, [title, description, jsonLd]); + + return null; +}; + +export default Seo; diff --git a/frontend/apps/artcraft-website/src/pages/faq/article.tsx b/frontend/apps/artcraft-website/src/pages/faq/article.tsx new file mode 100644 index 0000000000..09212276fb --- /dev/null +++ b/frontend/apps/artcraft-website/src/pages/faq/article.tsx @@ -0,0 +1,115 @@ +import { useMemo } from "react"; +import { useParams } from "react-router-dom"; +import Seo from "../../components/seo"; +import { parseFrontmatter, markdownToHtml } from "../../utils/markdown"; +import { Button } from "@storyteller/ui-button"; +import { faChevronLeft } from "@fortawesome/pro-solid-svg-icons"; + +const markdownFiles = import.meta.glob("./content/*.md", { + query: "?raw", + import: "default", + eager: true, +}); + +const FaqArticle = () => { + const { slug } = useParams(); + const entries = Object.entries(markdownFiles); + const markdown = (() => { + const byFilename = entries.find(([path]) => + path.endsWith(`/content/${slug}.md`) + ); + if (byFilename) return byFilename[1] as string; + for (const [_, raw] of entries) { + const { frontmatter } = parseFrontmatter(raw as string); + if ( + frontmatter.slug && + frontmatter.slug.trim().toLowerCase() === (slug || "").toLowerCase() + ) { + return raw as string; + } + } + return null; + })(); + const { frontmatter, body } = useMemo( + () => + markdown ? parseFrontmatter(markdown) : { frontmatter: {}, body: "" }, + [markdown] + ); + + if (!markdown) { + return ( +
+
+

Not found

+

We couldn't find this FAQ article.

+
+
+ ); + } + + const title = `${frontmatter.title || slug} - ArtCraft`; + const description = frontmatter.abstract || ""; + const thumbnail = frontmatter.thumbnail || ""; + const html = markdownToHtml(body, "/faq/"); + const jsonLd = { + "@context": "https://schema.org", + "@type": "Article", + headline: frontmatter.title || slug, + description: description, + articleBody: body, + }; + + return ( +
+ + +
+
+
+ +
+
+ +
+ +

+ {frontmatter.title || slug} +

+ {description &&

{description}

} + + {thumbnail && ( +
+ {frontmatter.title +
+ )} + +
+ +
+
+ ); +}; + +export default FaqArticle; diff --git a/frontend/apps/artcraft-website/src/pages/faq/content/2d-canvas.md b/frontend/apps/artcraft-website/src/pages/faq/content/2d-canvas.md new file mode 100644 index 0000000000..029f5b899c --- /dev/null +++ b/frontend/apps/artcraft-website/src/pages/faq/content/2d-canvas.md @@ -0,0 +1,26 @@ +--- +title: 2D Canvas — Draw and Generate +seoTitle: 2D Canvas — Sketch, mask, and guide AI generation +abstract: Draw, lay out references, and inpaint precisely to get the image you intended. +isPublished: true +publishedOn: 2025-10-06 +slug: 2d-canvas +--- + +## Draw first, generate second + +The 2D Canvas is a lightweight drawing and layout tool that the model respects. Sketch shapes, block the background, and mask areas to protect or change. When you generate, the structure you drew stays intact—only the fidelity improves. + +## What it’s great for + +- Storyboards, thumbnails, product mockups. +- Replacing elements in a scene without moving the rest. +- Fast “idea to image” iterations. + +## Tips + +- Use high‑contrast sketches for clearer guidance. +- Mask small areas for better local edits (logos, eyes, hands, reflections). +- Keep prompts short; the canvas already supplies structure. + +See also: [Text to Image](../text-to-image) · [Edit Image](../edit-image) · [3D Editor](../3d-editor) diff --git a/frontend/apps/artcraft-website/src/pages/faq/content/3d-editor.md b/frontend/apps/artcraft-website/src/pages/faq/content/3d-editor.md new file mode 100644 index 0000000000..12f0a26b29 --- /dev/null +++ b/frontend/apps/artcraft-website/src/pages/faq/content/3d-editor.md @@ -0,0 +1,27 @@ +--- +title: 3D Editor — Pose, Compose, and Generate +seoTitle: 3D Editor — Block scenes, pose characters, and render with AI +abstract: Build shots like a game, then render them consistently across angles and takes. +isPublished: true +publishedOn: 2025-10-06 +slug: 3d-editor +--- + +## Compose scenes like a playable set + +The 3D Editor lets you place subjects, cameras, and lights in a real‑time scene. Drag‑and‑drop images to create simple 3D proxies, pose characters, and orbit the camera until the shot feels right. When you generate, the AI keeps your framing and lighting intact. + +## Why 3D matters + +- Consistency across multiple shots and angles. +- Natural camera motion and depth cues. +- Character posing that matches your vision. + +## Workflow + +1. Choose a preset or import images to build the scene. +2. Place the subject, set the camera height and focal length. +3. Add a concise prompt for style and materials. +4. Generate, compare, and tweak until it clicks. + +See also: [Text to Image](../text-to-image) · [Image to Video](../image-to-video) · [2D Canvas](../2d-canvas) diff --git a/frontend/apps/artcraft-website/src/pages/faq/content/ai-image-generation-on-artcraft.md b/frontend/apps/artcraft-website/src/pages/faq/content/ai-image-generation-on-artcraft.md new file mode 100644 index 0000000000..16c4b01628 --- /dev/null +++ b/frontend/apps/artcraft-website/src/pages/faq/content/ai-image-generation-on-artcraft.md @@ -0,0 +1,36 @@ +--- +title: AI Image Generation on ArtCraft +seoTitle: AI Image Generation on ArtCraft +abstract: Explore ArtCraft's AI generation capabilities: features, workflows, and best practices. +isPublished: true +publishedOn: 2025-10-06 +slug: ai-image-generation-on-artcraft +--- + +## What is AI image generation in ArtCraft? + +ArtCraft brings modern AI image generation into a creator-first workflow that runs locally. You compose your idea on a 2D canvas or in a 3D scene, then guide the model to render the final image with consistency and control. The result is a fast loop for exploration, iteration, and polished outputs. + +## Core capabilities + +- 2D Canvas guidance: sketch layouts, place references, mask areas, and refine with inpainting. +- 3D Scene composition: set camera, lighting, and subject placement for consistent multi-shot renders. +- Structure-preserving generation: keep the arrangement you designed while improving detail and lighting. +- Revisions that respect intent: re-run specific regions to fix details without losing the overall look. + +## A simple workflow + +- Plan the shot: define focal point, subject scale, angle, and background (2D) or block out a scene (3D). +- Add guidance: references, masks, or prompts that clarify style, mood, and key details. +- Generate and iterate: compare candidates, refine regions, and lock in the final composition. + +## Quality and consistency tips + +- Favor clear subjects and readable silhouettes; the model follows strong structure best. +- Use concise prompts; describe style, lighting, and subject specifics with minimal filler. +- For multi-image sets, keep camera, distance, and lighting consistent between shots. +- Iterate locally on regions that need corrections (eyes, hands, logos, or textures). + +## Responsible use + +Only generate content you have the rights to create. Avoid infringing on other artists’ styles or producing deceptive media. When sharing, be transparent about AI involvement and follow relevant community and platform guidelines. diff --git a/frontend/apps/artcraft-website/src/pages/faq/content/edit-image.md b/frontend/apps/artcraft-website/src/pages/faq/content/edit-image.md new file mode 100644 index 0000000000..50bd50f926 --- /dev/null +++ b/frontend/apps/artcraft-website/src/pages/faq/content/edit-image.md @@ -0,0 +1,26 @@ +--- +title: Edit Image — Inpaint and Replace +seoTitle: Edit Image — Remove, replace, and restyle without Photoshop +abstract: Paint masks, describe the change, and let AI update only what you selected. +isPublished: true +publishedOn: 2025-10-06 +slug: edit-image +--- + +## Precise edits without leaving ArtCraft + +Edit Image lets you remove objects, fix details, or restyle parts of an image. Paint a mask, write a brief instruction, and generate. Only the masked region changes; the rest stays locked. + +## Common uses + +- Clean plates: remove cables, signage, or passers‑by. +- Product swaps: change colorways, logos, or materials. +- Portrait touch‑ups: hairline fixes, reflections, and lighting tweaks. + +## Tips + +- Keep masks tight around the area you want to change. +- Use short, clear instructions (e.g., “replace with polished chrome”). +- For multi‑step edits, work from big to small changes. + +See also: [2D Canvas](../2d-canvas) · [Text to Image](../text-to-image) diff --git a/frontend/apps/artcraft-website/src/pages/faq/content/generate-ai-photos-and-videos-of-yourself.md b/frontend/apps/artcraft-website/src/pages/faq/content/generate-ai-photos-and-videos-of-yourself.md new file mode 100644 index 0000000000..20d531255c --- /dev/null +++ b/frontend/apps/artcraft-website/src/pages/faq/content/generate-ai-photos-and-videos-of-yourself.md @@ -0,0 +1,31 @@ +--- +title: Generate AI photos and videos of yourself +seoTitle: Generate AI photos and videos of yourself in ArtCraft +abstract: Create photorealistic images of yourself by combining reference inputs with ArtCraft workflows. +isPublished: true +publishedOn: 2025-10-06 +slug: generate-ai-photos-and-videos-of-yourself +--- + +## Create AI portraits and short videos with strong likeness + +With ArtCraft you can generate images and short video clips of yourself while keeping control over pose, lighting, and style. The workflow combines good references with structure-aware generation so the results look like you—and stay consistent across shots. + +## What you need + +- A handful of clear photos that show your face from multiple angles, plus at least one full-body reference. +- Neutral lighting and no heavy filters. Avoid sunglasses or occlusions for the face. + +## Step-by-step + +1. Prepare references: choose 4–8 images that cover front, 3/4, and profile views; include one where your outfit and background match the vibe you want. +2. Set the composition: on the 2D canvas, sketch layout and subject scale, or use the 3D scene to place camera and lighting. +3. Guide the model: add a concise prompt describing mood, setting, and attire; use masks to protect areas you don’t want to change. +4. Generate and refine: compare candidates, then fix details with inpainting (eyes, hairlines, hands, accessories). +5. Make it move: for short clips, render a small set of frames from slight camera or pose variations, then export as a looping video. + +## Likeness and safety tips + +- Keep hair outline and eye region sharp in references; it improves identity consistency. +- Reuse the same camera distance and angle for a set; consistency beats variety for multi-shot galleries. +- Be mindful of where and how you publish. When sharing AI portraits, add context so viewers understand how they were made. diff --git a/frontend/apps/artcraft-website/src/pages/faq/content/image-to-video.md b/frontend/apps/artcraft-website/src/pages/faq/content/image-to-video.md new file mode 100644 index 0000000000..14eadfb3e2 --- /dev/null +++ b/frontend/apps/artcraft-website/src/pages/faq/content/image-to-video.md @@ -0,0 +1,27 @@ +--- +title: Image to Video in ArtCraft +seoTitle: Image to Video — Animate your images with AI video models +abstract: Turn a single image into a short, cinematic clip with controllable motion and style. +isPublished: true +publishedOn: 2025-10-06 +slug: image-to-video +--- + +## From still to motion in minutes + +Image to Video converts any image—your Text to Image result or a photo—into a short clip. Choose a video model, set duration and motion, then add a concise prompt to guide style and mood. + +## Best practices + +- Start from a clean, well‑lit image with a readable subject. +- Keep motion subtle for realism: camera drift, gentle parallax, or small pose changes. +- Use consistent prompts if you create a series of clips. + +## Workflow + +1. Pick a video model and duration. +2. Adjust motion options (camera, subject, or both). +3. Add a brief prompt for style and atmosphere. +4. Render, review, and export. + +See also: [Text to Image](../text-to-image) · [3D Editor](../3d-editor) · [Edit Image](../edit-image) diff --git a/frontend/apps/artcraft-website/src/pages/faq/content/models-supported.md b/frontend/apps/artcraft-website/src/pages/faq/content/models-supported.md new file mode 100644 index 0000000000..d85ba73555 --- /dev/null +++ b/frontend/apps/artcraft-website/src/pages/faq/content/models-supported.md @@ -0,0 +1,34 @@ +--- +title: What image and video models does ArtCraft support? +seoTitle: ArtCraft models — Image and Video generation models +abstract: A quick overview of image and video models available in ArtCraft. +isPublished: true +publishedOn: 2025-10-06 +slug: models-supported +--- + +## Image models + +- Flux Pro 1.1 Ultra +- Flux Pro 1.1 +- Flux 1 Dev +- Flux 1 Schnell +- Midjourney +- GPT Image 1 +- Gemini 2.5 Flash (editing) +- Flux Pro Kontext Max (editing) +- Flux Pro Inpaint (editing) +- Flux Dev Juggernaut Inpaint (editing) + +## Video models + +- Kling 1.6 Pro +- Kling 2.1 Pro +- Kling 2.1 Master +- Seedance 1.0 Lite +- Sora 2 +- Google Veo 2 +- Google Veo 3 +- Google Veo 3 Fast + +See also: [Text to Image](../text-to-image) · [Image to Video](../image-to-video) diff --git a/frontend/apps/artcraft-website/src/pages/faq/content/text-to-image.md b/frontend/apps/artcraft-website/src/pages/faq/content/text-to-image.md new file mode 100644 index 0000000000..67ceef43b5 --- /dev/null +++ b/frontend/apps/artcraft-website/src/pages/faq/content/text-to-image.md @@ -0,0 +1,28 @@ +--- +title: Text to Image in ArtCraft +seoTitle: Text to Image — Prompt and generate with top AI models +abstract: Turn ideas into images with clean prompts, model choices, and consistent structure. +isPublished: true +publishedOn: 2025-10-06 +slug: text-to-image +--- + +## Turn prompts into polished images + +Text to Image in ArtCraft lets you move quickly from idea to result. Choose a model, write a clear prompt, and render. If you need more control, sketch a loose layout on the 2D canvas or block a scene in 3D first—generation will respect your composition. + +## Tips for great prompts + +- Be specific about subject, action, and style (lighting, lens, materials). +- Prefer short, descriptive phrases over long paragraphs. +- Use negative cues sparingly (e.g., “no text, no watermark”). + +## Choose the right model + +Different models excel at different looks. For photorealism, use a high‑fidelity model. For design and branding, choose a model that handles flat color and typography well. If speed matters, start with a fast model to explore options, then switch to a higher‑quality model for final renders. + +## Iterate with structure + +If the result is close but not perfect, keep the composition and re‑render small regions with inpainting. This preserves the framing while fixing details like hands, logos, or textures. + +See also: [2D Canvas](../2d-canvas) · [3D Editor](../3d-editor) · [Edit Image](../edit-image) diff --git a/frontend/apps/artcraft-website/src/pages/faq/index.tsx b/frontend/apps/artcraft-website/src/pages/faq/index.tsx new file mode 100644 index 0000000000..34a8d76352 --- /dev/null +++ b/frontend/apps/artcraft-website/src/pages/faq/index.tsx @@ -0,0 +1,74 @@ +import { Link } from "react-router-dom"; +import Seo from "../../components/seo"; +import { parseFrontmatter, pathToFilename } from "../../utils/markdown"; + +const faqFiles = import.meta.glob("./content/*.md", { + query: "?raw", + import: "default", + eager: true, +}); + +const FaqIndex = () => { + const title = "Frequently Asked Questions - ArtCraft"; + const description = + "Explore ArtCraft FAQs: guides on AI image generation, editing, and workflows."; + + const items = Object.entries(faqFiles).map(([path, raw]) => { + const { frontmatter } = parseFrontmatter(raw as string); + const slug = pathToFilename(path); + return { + slug, + title: frontmatter.title || slug, + description: frontmatter.abstract || "", + }; + }); + + const jsonLd = { + "@context": "https://schema.org", + "@type": "FAQPage", + mainEntity: items.map((item) => ({ + "@type": "Question", + name: item.title, + acceptedAnswer: { + "@type": "Answer", + text: item.description, + }, + })), + }; + + return ( +
+ + +
+
+
+ +
+
+

+ Frequently Asked Questions +

+

+ Deep-dive guides and answers about ArtCraft. +

+
+ +
+ {items.map((item) => ( + +

{item.title}

+

{item.description}

+ + ))} +
+
+
+ ); +}; + +export default FaqIndex; diff --git a/frontend/apps/artcraft-website/src/pages/index.ts b/frontend/apps/artcraft-website/src/pages/index.ts index 0f9d35ba27..29627e4d79 100644 --- a/frontend/apps/artcraft-website/src/pages/index.ts +++ b/frontend/apps/artcraft-website/src/pages/index.ts @@ -2,3 +2,6 @@ export * from "./landing"; export * from "./landing2"; export * from "./download"; export * from "./tutorials"; +export { default as TutorialsIndex } from "./tutorials/md-index"; +export { default as TutorialsArticle } from "./tutorials/article"; +export * from "./faq"; diff --git a/frontend/apps/artcraft-website/src/pages/landing2/landing2.tsx b/frontend/apps/artcraft-website/src/pages/landing2/landing2.tsx index 1fb14f8427..9835e27a94 100644 --- a/frontend/apps/artcraft-website/src/pages/landing2/landing2.tsx +++ b/frontend/apps/artcraft-website/src/pages/landing2/landing2.tsx @@ -102,7 +102,7 @@ const Landing = () => {
-
+
{/* Main Heading */} { {/* Glassy Video Mockup */}
setIsHovering(true)} onMouseLeave={() => setIsHovering(false)} > @@ -184,7 +184,7 @@ const Landing = () => { autoPlay loop playsInline - className="w-full h-full object-cover rounded-2xl" + className="w-full h-full object-cover rounded-2xl bg-white" src="https://pub-f7441936e5804042a1ea2bdc92e4dc71.r2.dev/artcraft_commercial.mp4" > { + const { slug } = useParams(); + + const entries = Object.entries(tutorialFiles); + const markdown = (() => { + // 1) filename match + const byFilename = entries.find(([path]) => + path.endsWith(`/content/${slug}.md`) + ); + if (byFilename) return byFilename[1] as string; + // 2) frontmatter slug match + const wanted = (slug || "").toLowerCase(); + for (const [_, raw] of entries) { + const { frontmatter } = parseFrontmatter(raw as string); + const fmSlug = (frontmatter.slug || "").trim().toLowerCase(); + if (fmSlug && fmSlug === wanted) return raw as string; + const aliasesRaw = (frontmatter.aliases || "").toString(); + if (aliasesRaw) { + const candidateList = aliasesRaw + .split(/[\s,]+/) + .map((s) => s.trim().toLowerCase()) + .filter(Boolean); + if (candidateList.includes(wanted)) return raw as string; + } + } + return null; + })(); + const { frontmatter, body } = useMemo( + () => + markdown ? parseFrontmatter(markdown) : { frontmatter: {}, body: "" }, + [markdown] + ); + + if (!markdown) { + return ( +
+
+

Not found

+

We couldn't find this tutorial.

+
+
+ ); + } + + const title = `${frontmatter.title || slug} - ArtCraft`; + const description = frontmatter.abstract || ""; + const toEmbed = (url: string): string => { + if (!url) return url; + if (url.includes("youtu.be/")) + return url.replace("youtu.be/", "www.youtube.com/embed/"); + if (url.includes("watch?v=")) return url.replace("watch?v=", "embed/"); + return url; + }; + const frontmatterVideo = + (frontmatter.videoUrl as string) || + (frontmatter.youtubeId + ? `https://www.youtube.com/embed/${frontmatter.youtubeId}` + : ""); + const videoUrl = toEmbed(frontmatterVideo); + const html = markdownToHtml(body); + const jsonLd = { + "@context": "https://schema.org", + "@type": "Article", + headline: frontmatter.title || slug, + description: description, + articleBody: body, + }; + + return ( +
+ + +
+
+
+ +
+
+ +
+ +

+ {frontmatter.title || slug} +

+ {description &&

{description}

} + + {videoUrl && ( +
+