Panda IDX

Canvas

Build visual demonstrations and marketing pages with the Canvas system using absolute positioning, animations, and semantic HTML. Advanced page builder for creating stunning real estate marketing pages.

Overview

The Canvas system (@panda/visuals) lets you create visual compositions with absolute positioning and smooth animations - think of it as Adobe After Effects for React, now with built-in SEO optimization.

Perfect for:

  • Product demos and mockups
  • Marketing page visuals
  • Interactive presentations
  • Feature showcases

Built on Framer Motion for performant animations, and uses semantic HTML5 (<figure>) for better accessibility and SEO.


Quick Start

Install & Import

import { Canvas, CanvasElement } from "@panda/visuals"

Create Your First Canvas

<Canvas width={1200} height={800} background="ocean">
  <CanvasElement
    position={{ x: 100, y: 100 }}
    size={{ w: 400, h: 300 }}
  >
    <YourComponent />
  </CanvasElement>
</Canvas>

Add SEO (Optional - Marketing Pages Only)

<Canvas
  ariaLabel="Product dashboard showing key metrics"
  seoMetadata={{
    title: "Dashboard Interface",
    description: "Visual demonstration of...",
    features: ["Feature 1", "Feature 2"]
  }}
>
  {/* Your visual */}
</Canvas>

Components

Canvas

A fixed-size container for absolutely positioned elements. Always renders as <figure role="img"> for semantic HTML, accessibility, and SEO.

Core Props

PropTypeDefaultDescription
widthnumber800Canvas width in pixels
heightnumber600Canvas height in pixels
backgroundstring"ocean"Gradient variant or custom CSS
overflowstring"hidden""visible" or "hidden"
classNamestring""Additional CSS classes

SEO & Accessibility Props

PropTypeDefaultDescription
ariaLabelstring"Visual demonstration"Screen reader label
seoMetadataobjectnullSEO metadata (see below)

v2.0 Breaking Change: Canvas now always renders as <figure>. Props fallbackImage and role have been removed.

seoMetadata Structure

{
  title: string           // "Feature Name" (50-70 chars)
  description: string     // Detailed description (150-200 words)
  features: string[]      // Array of 5-10 features
}

Background Gradients

Built-in presets: ocean (default), sunset, dusk, forest, sunrise, midnight, lavender, tropical, autumn, aurora

Or custom CSS: background="linear-gradient(...)"


Usage Examples

Basic Usage

For internal dashboards or when SEO isn't needed:

<Canvas width={1200} height={800} background="ocean">
  <CanvasElement
    position={{ x: 100, y: 100 }}
    size={{ w: 400, h: 300 }}
  >
    <DashboardPreview />
  </CanvasElement>
</Canvas>

Renders as:

<figure role="img" aria-label="Visual demonstration">
  <div style="width: 1200px; height: 800px">
    <!-- Your content -->
  </div>
</figure>

With SEO Metadata

For marketing pages where you want search visibility:

<Canvas
  width={1450}
  height={850}
  ariaLabel="Real estate CRM pipeline with drag-and-drop deal tracking"
  seoMetadata={{
    title: "Transaction Pipeline Management",
    description: "Visual demonstration of Panda CRM's pipeline system featuring drag-and-drop deal tracking, automated stage progression, and customizable workflows for real estate transactions.",
    features: [
      "Drag-and-drop deal management across stages",
      "Automated task creation and deadline tracking",
      "Custom pipeline stages for property types",
      "Real-time team collaboration",
      "Email and SMS integration"
    ]
  }}
>
  <CanvasElement>
    <PipelineDemo />
  </CanvasElement>
</Canvas>

Includes hidden but crawlable <figcaption>:

<figcaption class="sr-only" aria-hidden="false">
  <h3>Transaction Pipeline Management</h3>
  <p>Visual demonstration of...</p>
  <ul>
    <li>Drag-and-drop deal management...</li>
    <!-- More features -->
  </ul>
</figcaption>

Real Marketing Example

From the CRM landing page hero section:

<Canvas
  width={1450}
  height={850}
  background="transparent"
  overflow="visible"
  ariaLabel="Panda CRM Contact Dashboard - lead tracking and client management"
  seoMetadata={{
    title: "Real Estate CRM Contact Management Interface",
    description: "Visual demonstration of Panda CRM's contact management featuring AI-powered inbox, automated lead source tracking, and intelligent client segmentation. Manage unlimited real estate contacts with multi-channel communication including email, phone, and WhatsApp integration.",
    features: [
      "AI-powered contact search with natural language",
      "Automatic lead source attribution from 10+ channels",
      "Client stage tracking (Active, Nurturing, Closed)",
      "Multi-channel messaging (Email, Phone, WhatsApp)",
      "Birthday and anniversary reminder automation",
      "Custom segmentation by price, location, stage",
      "Real-time team collaboration",
      "100MB document storage per contact"
    ]
  }}
>
  <CanvasElement
    position={{ x: 0, y: 80 }}
    size={{ w: 1500, h: 850 }}
    rounded={32}
    borderWidth={12}
    shadow={{ y: 40, blur: 80 }}
  >
    <ContactsDashboard />
  </CanvasElement>
</Canvas>

SEO Best Practices

When to Add SEO

✅ Add seoMetadata to:

  • Landing pages (/real-estate-crm, /idx-website)
  • Product feature showcases
  • Marketing pages (unauthenticated)
  • Public demos

❌ Skip seoMetadata for:

  • Internal dashboards (behind login)
  • Admin panels
  • User-specific content
  • Development/staging environments

Writing Good ariaLabel

Describe what a user sees in the visual.

✅ Good Examples:

"CRM contact table with 247 leads and price filters"
"Transaction pipeline showing 12 deals across 5 stages"
"Email inbox with client conversations and search"

❌ Bad Examples:

"Visual demonstration"  // Too generic
"Canvas component"       // Technical detail
"Screenshot"            // Not descriptive

Tip: Read your ariaLabel out loud. If someone could draw a rough sketch from it, it's good.

SEO Metadata Guidelines

Title (50-70 characters)

  • Include primary keyword ("Real Estate CRM")
  • Describe the specific feature shown
  • Will be rendered as <h3> in figcaption
title: "Real Estate CRM Contact Management Interface"
title: "Transaction Pipeline with Drag-and-Drop"
title: "AI-Powered Email Inbox for Real Estate"

Description (150-200 words)

  • Expand on what's visible in the screenshot
  • Include secondary keywords naturally
  • Mention integrations and capabilities
  • Focus on benefits, not just features

Features (5-10 items)

  • Specific, measurable features
  • Include technical details ("100MB storage")
  • Mention integrations ("WhatsApp, Telegram")
  • Use action-oriented language

Only describe features visible in the visual. Don't mention AI if it's not shown.


Accessibility

How Screen Readers Announce

<Canvas ariaLabel="CRM dashboard with lead tracking">
  {/* content */}
</Canvas>

Screen reader: "Image: CRM dashboard with lead tracking"

Figcaption Behavior

When seoMetadata is provided:

  • <figcaption> has class="sr-only" (visually hidden)
  • aria-hidden="false" lets screen readers access it
  • Search engines crawl the full text

Best for: Marketing pages Skip for: Internal tools


Responsiveness

When to Use ResponsiveCanvas

Canvas uses fixed pixel dimensions by default. For responsive layouts (especially marketing pages), wrap Canvas in <ResponsiveCanvas>.

✅ Use ResponsiveCanvas for:

  • Marketing/landing pages - Needs to work on all screen sizes
  • Public-facing demos - Viewed on desktop, tablet, and mobile
  • Hero sections - Full-width responsive visuals
  • Feature showcases - Adapts to viewport width

❌ Use Canvas alone for:

  • Internal dashboards - Typically desktop-only
  • Fixed layouts - When you control the container size
  • Admin panels - Desktop-first applications
  • Embed contexts - When container size is known

How ResponsiveCanvas Works

Automatically scales the Canvas to fit the viewport while maintaining aspect ratio:

import { ResponsiveCanvas, Canvas, CanvasElement } from "@panda/visuals"

<ResponsiveCanvas
  canvasWidth={1450}   // Original design width
  canvasHeight={850}   // Original design height
  minHeight={400}      // Minimum height on small screens
>
  <Canvas width={1450} height={850} background="transparent">
    <CanvasElement position={{ x: 100, y: 100 }} size={{ w: 400, h: 300 }}>
      <YourVisual />
    </CanvasElement>
  </Canvas>
</ResponsiveCanvas>

What happens:

  • Desktop (1450px+): Shows at full size (scale: 1)
  • Tablet (768-1449px): Scales down proportionally
  • Mobile (under 768px): Scales to fit width, minimum 400px height

With Animations

ResponsiveCanvas supports Framer Motion animations:

<ResponsiveCanvas
  canvasWidth={1450}
  canvasHeight={850}
  initial={{ opacity: 0, y: 100 }}
  whileInView={{ opacity: 1, y: 0 }}
  viewport={{ once: true }}
  transition={{ duration: 0.5 }}
>
  <Canvas>{/* Your visual */}</Canvas>
</ResponsiveCanvas>

Tip: Use ResponsiveCanvas for scroll-triggered animations on landing pages. It handles both scaling AND animation.

ResponsiveCanvas Props

PropTypeDefaultDescription
canvasWidthnumber1450Original canvas width
canvasHeightnumber850Original canvas height
minHeightnumber400Minimum height on mobile
classNamestring""Additional CSS classes
childrenReactNode-Canvas component(s)

Plus all Framer Motion props: initial, animate, whileInView, transition, etc.


CanvasElement

Absolutely positioned element with animation support. Use inside Canvas to position content.

Key Props

Position & Size

PropTypeDefault
position{x, y}{x:0, y:0}
size{w, h}{w:100, h:100}
zoomnumber1
zIndexnumber0

Styling

PropTypeDefault
roundednumber0
opacitynumber1
borderWidthnumber0
borderColorstringrgba(...)

Shadow

shadow={{
  x: 0,
  y: 20,
  blur: 40,
  spread: 0,
  color: "rgba(0,0,0,0.2)"
}}

Or use presets: "sm", "md", "lg", "xl", "2xl", "3xl"

3D Perspective

perspective={{
  rotateX: 5,
  rotateY: -8,
  perspective: 1500
}}

Filters

PropTypeDescription
blurnumberBlur in pixels
brightnessnumberBrightness %

Animation Props

All Framer Motion props supported:

  • initial, animate, exit
  • transition
  • whileHover, whileTap, whileInView
  • viewport (for scroll animations)
  • drag, dragConstraints

Animation Presets

Pre-built animations for common patterns.

import { AnimationPresets } from "@panda/visuals"

<CanvasElement {...AnimationPresets.fadeIn}>
  {/* Content */}
</CanvasElement>

Available Presets

Entrance: fadeIn, slideUp, slideDown, slideLeft, slideRight, scaleIn

Loop: float, rotate, pulse, breathe, swing

Hover: lift, grow, glow, tilt

Tap: press, bounce

Combined: fadeInAndFloat, slideInWithLift

Helpers

import { combinePresets, withStagger } from "@panda/visuals"

// Combine animations
const combined = combinePresets(
  AnimationPresets.fadeIn,
  AnimationPresets.lift
)

// Stagger children
const staggered = withStagger(AnimationPresets.slideUp, 0.1)

Complete Examples

Layered Composition

<Canvas background="sunrise" width={1400} height={900} overflow="visible">
  {/* Background layer */}
  <CanvasElement
    position={{ x: 50, y: 50 }}
    size={{ w: 800, h: 600 }}
    zIndex={1}
    shadow={{ y: 30, blur: 50 }}
    {...AnimationPresets.fadeIn}
  >
    <BackgroundVisual />
  </CanvasElement>

  {/* Foreground layer */}
  <CanvasElement
    position={{ x: 200, y: 150 }}
    size={{ w: 600, h: 400 }}
    zIndex={2}
    rounded={24}
    borderWidth={12}
    borderColor="rgba(255, 255, 255, 0.2)"
    shadow={{ y: 40, blur: 60 }}
    perspective={{ rotateX: 5, rotateY: -8, perspective: 1500 }}
    {...AnimationPresets.slideInWithLift}
  >
    <ForegroundVisual />
  </CanvasElement>
</Canvas>

Custom Animation

<CanvasElement
  position={{ x: 0, y: 0 }}
  size={{ w: 400, h: 300 }}
  initial={{ opacity: 0, scale: 0.5 }}
  animate={{ opacity: 1, scale: 1 }}
  transition={{ duration: 0.8, ease: "easeOut" }}
  whileHover={{ scale: 1.05, y: -10 }}
>
  <ProductCard />
</CanvasElement>

Best Practices

Performance

  • Use overflow="hidden" when possible for better rendering
  • Limit simultaneous animations on screen
  • Prefer transform animations (scale, rotate, translate) over layout changes

Positioning

  • Use absolute pixel values for precision
  • Calculate responsive positions based on viewport
  • Use zIndex for overlapping elements

Animations

  • Start with presets, customize as needed
  • Use whileInView for scroll-triggered animations
  • Combine with combinePresets() for complex effects

SEO & Accessibility

  • Always add descriptive ariaLabel (don't use default)
  • Add seoMetadata to marketing pages only
  • Write features as complete sentences
  • Include industry keywords naturally
  • Skip SEO on authenticated pages