Skip to main content

Overview

Assets are static files such as images, fonts, videos, and icons used in your Tesslate Studio projects. The platform provides upload, organization, and storage capabilities backed by S3-compatible object storage, with metadata tracked in the ProjectAsset database model.

Drag-and-Drop Upload

Upload files by dragging them into the assets panel or clicking the upload button

S3 Storage

Assets stored in S3-compatible storage with the “S3 Sandwich” pattern

Metadata Tracking

File type, dimensions, MIME type, and directory tracked in the database

Organized by Directory

Folder-based organization within your project structure

Asset Types

Photos and graphicsSupported formats:
  • PNG, JPG, JPEG
  • WebP, SVG
  • GIF, AVIF
The ProjectAsset model stores width and height for image files, making it easy to reference dimensions in your code.

Uploading Assets

1

Open the Assets Panel

Click Assets in the project sidebar to open the assets management panel.
2

Choose Upload Method

Three ways to add assets:
  • Drag and drop: Drag files directly onto the assets panel
  • Upload button: Click Upload and browse your file system
  • Clipboard paste: Paste an image from your clipboard
3

Select Files

Choose one or multiple files. Supported formats are validated before upload.
4

Upload and Process

Files are uploaded to S3 storage. Metadata (filename, directory, file_path, file_type, mime_type, width, height) is recorded in the ProjectAsset table.
5

Use in Code

Uploaded assets appear in the file tree and are immediately available to import or reference in your code.
Images under 1MB upload and process quickly. Larger files may take a moment depending on your connection speed.

The S3 Sandwich Pattern

Tesslate uses an architecture pattern called the “S3 Sandwich” for asset storage. This pattern places S3-compatible object storage between the application layer and the user’s project containers.

How It Works

1

Upload Layer

When you upload an asset, the file goes from the browser to the Tesslate backend (FastAPI).
2

S3 Storage Layer

The backend stores the file in an S3-compatible bucket (AWS S3 in production, MinIO for local development). The bucket is configured via the S3_BUCKET_NAME environment variable.
3

Container Access Layer

Project containers access assets through the shared storage. In Kubernetes mode, assets are accessible via the project’s persistent volume. In Docker mode, assets are available through the mounted project directory.

Why S3 Sandwich?

BenefitDescription
PersistenceAssets survive container restarts and hibernation
Shared AccessMultiple containers in a project can access the same assets
ScalabilityS3 scales independently of compute resources
BackupAssets are stored separately from ephemeral container state

Configuration

Environment VariablePurposeExample
S3_BUCKET_NAMEPrimary storage buckettesslate-projects-prod
S3_ENDPOINT_URLS3 endpoint (for MinIO or non-AWS)http://minio:9000
AWS_ACCESS_KEY_IDS3 access credentials(from secrets)
AWS_SECRET_ACCESS_KEYS3 secret credentials(from secrets)
In local Docker development, Tesslate uses MinIO as an S3-compatible replacement. The API is identical, so code works the same in development and production.

Using Assets in Code

Importing Images

// Import from assets folder (processed by Vite bundler)
import heroImage from './assets/hero.png'
import logo from './assets/logo.svg'

// Use in components
function Hero() {
  return (
    <div>
      <img src={logo} alt="Logo" />
      <img src={heroImage} alt="Hero" />
    </div>
  )
}

Public Folder

For assets that do not need bundler processing:
// Files in public/ folder are served directly by path
<img src="/images/hero.png" alt="Hero" />
<link rel="icon" href="/favicon.svg" />

Background Images

// CSS background images
<div style={{
  backgroundImage: `url('/images/background.jpg')`
}} />

// Or with Tailwind CSS
<div className="bg-[url('/images/bg.jpg')]" />

Asset Organization

src/assets/
  images/
    hero/
    products/
    icons/
  fonts/
    custom/
  videos/
    demos/

public/
  favicon.svg
  logo.png
  social-preview.jpg
Processed by the build tool (Vite)
  • Imported in components via import statements
  • Bundled and optimized during build
  • Filenames get content hashes for cache busting
  • Best for: Component images, icons, fonts used in React code
Served directly without processing
  • Not processed by the bundler
  • Filenames stay the same
  • Referenced by URL path
  • Best for: Favicon, social media images, PDFs, files that need stable URLs

Asset Metadata

The ProjectAsset model tracks detailed metadata for each uploaded file:
FieldDescription
filenameOriginal file name
directoryDirectory path within the project
file_pathFull path to the asset
file_typeCategory: image, font, video, audio, other
mime_typeMIME type (e.g., image/png, font/woff2)
widthImage width in pixels (images only)
heightImage height in pixels (images only)
This metadata powers the assets panel UI, enabling previews, dimension display, and type-based filtering.

Fonts

Adding Custom Fonts

1

Upload Font Files

Upload .woff2, .woff, or .ttf files to the assets panel
2

Create Font Face CSS

Ask the AI agent: “Add custom font Inter to the project”The agent generates:
@font-face {
  font-family: 'Inter';
  src: url('/fonts/Inter-Regular.woff2') format('woff2');
  font-weight: 400;
  font-display: swap;
}
3

Configure Tailwind

Update your Tailwind config:
// tailwind.config.js
fontFamily: {
  sans: ['Inter', 'sans-serif']
}

Google Fonts

For convenience, you can also use Google Fonts without uploading files:
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link
  href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
  rel="stylesheet"
/>

Icons

Using Lucide Icons (Built-in)

Tesslate projects include Lucide React by default:
import { Home, User, Settings, ShoppingCart } from 'lucide-react'

function Navigation() {
  return (
    <nav>
      <Home className="w-6 h-6" />
      <User className="w-6 h-6" />
      <Settings className="w-6 h-6" />
      <ShoppingCart className="w-6 h-6" />
    </nav>
  )
}

Custom SVG Icons

Upload SVGs to your assets and import them:
import { ReactComponent as CustomIcon } from './assets/icons/custom.svg'

<CustomIcon className="w-6 h-6" />

Responsive Images

Ask the AI agent to create responsive image components:
<picture>
  <source
    media="(min-width: 1024px)"
    srcSet="/images/hero-large.webp"
  />
  <source
    media="(min-width: 768px)"
    srcSet="/images/hero-medium.webp"
  />
  <img
    src="/images/hero-small.webp"
    alt="Hero"
    loading="lazy"
  />
</picture>

Best Practices

  • Compress images before uploading
  • Resize to the dimensions you actually need
  • Remove unnecessary metadata (EXIF data)
  • Use appropriate quality settings (80% JPEG quality is usually sufficient)
  • WebP for photographs and complex images
  • SVG for logos, icons, and simple graphics
  • AVIF for best compression when browser support allows
  • PNG only when transparency is needed and SVG is not suitable
  • Host videos on YouTube or Vimeo and embed them
  • Use Cloudinary or imgix for heavy image processing
  • Keep your S3 bucket focused on project-essential assets
  • hero-background.jpg instead of IMG_1234.jpg
  • product-thumbnail.png instead of image-2.png
  • Descriptive names improve organization and SEO

Deleting Assets

1

Check References

Before deleting, verify the asset is not used in any component or stylesheet
2

Delete

Right-click the asset in the assets panel and select Delete
3

Confirm

Confirm the deletion. This removes the file from S3 storage and the ProjectAsset database record.
Deleting an asset that is still referenced in your code will cause broken images or missing files. Always check usage before deleting.

Troubleshooting

Solutions:
  • Check the file path is correct (case-sensitive on Linux)
  • Verify the file uploaded successfully in the assets panel
  • Check the browser console for 404 errors
  • Ensure the import syntax matches the file location (src/assets/ vs public/)
  • Try an absolute path (e.g., /images/file.jpg)
Solutions:
  • Compress images before uploading
  • Use WebP format instead of PNG or JPEG
  • Add loading="lazy" to images below the fold
  • Generate responsive sizes for different viewports
Solutions:
  • Check file size (recommended max: 10MB per file)
  • Verify the file format is supported
  • Check your internet connection
  • Verify S3 storage is configured and accessible
  • Try compressing the file and retrying

Next Steps

Code Editor

Import and use assets in your code

Using Agents

Ask AI to optimize images or create responsive components

Projects

Understand project structure and file organization

Live Preview

See your assets rendered in the live preview