Assets
Images, icons, logos and fonts in a design.
Fonts
- Any Google font is available. Put the family in a font token:
--font-display: 'Fraunces', ui-serif, Georgia, serif. Knighn writes one Google Fonts link for the families and the weights that the design uses. - Set weights with classes such as
font-mediumandfont-semibold. Knighn loads the weights that the classes use. --font-sansis the default font of all text. Headings usefont-display, and code usesfont-mono.- Always add fallbacks after the family, so that the text shows before the font loads.
- A system font, such as SF Pro, is only a name. Knighn never uploads it, because of its licence. It shows only on devices that have it. Add system fallbacks:
'SF Pro Text', -apple-system, BlinkMacSystemFont, system-ui, sans-serif. - A custom font file is an asset. The user adds it in the app, and Knighn writes an
@font-facerule in the theme block. - Find fonts with the search tool, kind
font.
Two families are enough for most designs: one for headings and one for body text. Use one family in different weights for a quiet design.
Images
- Use images that the user gave you or asked for. Never make up an image URL.
- Put each image into Knighn storage with
UploadImage. It returns a URL such ashttps://share.knighn.com/a/<sha256>.jpg. Use that URL in the design, so the design does not depend on the site of the image. - The URL comes from the content of the file. The same bytes always give the same URL, and the URL never changes.
- Anyone with the URL can see the image. Ask the user before you upload a private image.
- When you have no image, put a placeholder with a name and a muted fill:
<div data-name="Product photo" className="aspect-video rounded-xl bg-muted" />. - When the person asks for a new picture,
GenerateImage(prompt, { kind: 'photo' })or{ kind: 'logo' }makes one with Codex on their Mac and returns its Knighn URL. It works only in the Knighn app on a Mac and on the Knighn daemon.
Show an image with img, object-cover and a box with a size:
const src = await UploadImage('https://images.example.com/team.jpg') // a URL that the user gave you
const [media] = Find(page, '[data-name="Hero image"]')
Replace(
media,
`<img data-name="Hero image" src="${src}" alt="Four people around a table with laptops" className="aspect-[4/3] w-full rounded-2xl object-cover" />`
)
For an image behind content, use a background class:
const bg = await UploadImage('https://images.example.com/coast.jpg') // a URL that the user gave you
const [hero] = Find(page, '[data-name="Hero"]')
Update(hero, { classes: `bg-[url(${bg})] bg-cover bg-center` })
When you export a design as one file, Knighn puts the images into the file. When Knighn opens the file again, it uploads them again and puts the URLs back.
SVG
Inline <svg> elements are allowed. Use the JSX spelling of the attributes, such as strokeWidth and strokeLinecap.
- Use
fill="currentColor"orstroke="currentColor", so that text colour classes set the colour. - Set the size with classes:
size-5. - Always keep the
viewBox. - Do not draw logos or illustrations as paths. For a brand logo, use
InsertLogo. For other art, use an image, or a placeholder with a name. - To make a logo image into paths, use
TraceImage(image, { replace: true }). potrace on the person's Mac traces it.
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
className="size-5 text-accent"
>
<path d="M20 6 9 17l-5-5" />
</svg>
Icons
Write <Icon name="shield-check" className="size-5 text-accent" /> in the TSX that you give to Define, AddScreen, Insert, Replace or a tsx block. Knighn puts the Lucide icon there as an inline <svg> before it reads the TSX, so no call is necessary for each icon. Find icon names with the search tool, kind icon.
nameis a Lucide name. Common names of other sets also work, such as the Font Awesomearrow-rotate-right(Luciderotate-cw),gear,xmarkandmagnifying-glass. An unknown name stops the call and gives the close names.size={16}addssize-4. Without a size class, the icon is 24 px (size-6). A text colour class colours it.strokeWidth={1.5}changes the stroke.aria-label="Reload"gives the icon a name; otherwise it getsaria-hidden.- Write the name as text.
name={icon}does not work, because an instance cannot choose an icon by a prop. - In a slot, such as
icon={<Icon name="plus" className="size-4" />}, Knighn makes a small icon component, such asIconPlus, and gives the slot an instance of it. - When the design defines its own
Iconcomponent, Knighn leaves<Icon>as it is.
InsertIcon(parent, name, { className }) puts an icon into a layer that exists:
const [feature] = Find(page, '[data-name="Feature icon"]')
await InsertIcon(feature, 'shield-check', { className: 'size-5 text-accent' })
- Use one icon set and one stroke width in a design.
- Use 16 px icons with 14 px text, and 20 px icons with 16 px text.
- For an icon in a slot, write
<Icon>in the slot:icon={<Icon name="bell" />}.
Logos
For the logo of a company, a product or a tool (Stripe, GitHub, Figma, Vercel), use the real logo from svgl (svgl.app). InsertLogo(parent, name, { theme, wordmark, className }) puts it into a layer as an inline <svg> with the brand colours. Find logos with the search tool, kind logo, or with await SearchLogos(name).
const [row] = Find(page, '[data-name="Customer logos"]')
for (const brand of ['Stripe', 'GitHub', 'Figma', 'Vercel']) {
await InsertLogo(row, brand, { className: 'h-8 w-auto' })
}
- Never use an emoji, a Lucide icon or a drawn shape for a brand logo. Lucide icons are for actions and ideas, not for brands.
- Use
theme: 'dark'on a dark background. A logo that is black on white has a white version for dark backgrounds. - Use
wordmark: truefor the logo with the name, when svgl has one. Otherwise put the name next to the mark as text. - Set the height and keep the width automatic:
h-8 w-auto. Do not stretch a logo. - When svgl has no logo for the brand, ask the person for the logo file and bring it in with
UploadImage(url). Do not draw one. InsertLogoaddsrole="img"and anaria-labelwith the brand name.
Alt text and labels
- Give each
imganaltthat says what the image shows. Knighn warns withlint/img-altwhen it is missing. - Use
alt=""for an image that is only decoration. - Give each button that has only an icon an
aria-label:<button type="button" aria-label="Close">. - Give each decorative
<svg>the attributearia-hidden="true". - Use real headings in order: one
h1for each screen, thenh2andh3.