Skip to main content

Widgets

Transform your digital signage with powerful, data-driven templates

Widgets are the core building blocks of Castmill's template system, enabling you to create sophisticated, dynamic digital signage content ranging from elegant restaurant menus and airport information panels to weather displays, news tickers, and transit schedules. Through a declarative JSON format, widgets combine visual components, data binding, and animations to deliver professional, engaging content without writing code.

What Are Widgets?​

A widget is a JSON-based template that defines how content should be displayed on your digital signage screens. Think of widgets as reusable blueprints that can be populated with different data, styled with CSS, and enhanced with animationsβ€”all through a simple, declarative format.

Key Features​

  • 🎨 Component-Based: Build complex layouts using simple, composable components
  • πŸ“Š Data-Driven: Bind external data sources to create dynamic, real-time content
  • 🎬 Animation Support: Leverage GSAP animations for smooth, professional transitions
  • πŸ“± Responsive: Full CSS support for creating adaptive, multi-resolution designs
  • πŸ”„ Auto-Updating: Configure automatic data refresh intervals
  • 🎯 Type-Safe: Schema validation ensures data integrity

Quick Start​

Let's create your first widgetβ€”a simple image display. You can see both the JSON definition and a live preview of how it renders:

Simple Image Widget

A basic widget that displays a static image with cover sizing.

Loading widget player...

This widget displays an image for 10 seconds. The options_schema defines what data the widget needs, while the template describes how to render it. Toggle between showing the code and preview using the buttons above!

🎯 Best Practice: Responsive Units​

Critical: Always Use Relative Units

Never use absolute pixel units (px) in your widgets! Digital signage displays come in many resolutions (1080p, 4K, vertical displays, etc.). Using pixels will make your widget look different on each screen size.

βœ… Use these relative units instead:

  • em - Relative to the element's font size (best for padding, margins, borders)
  • rem - Relative to the root font size (good for consistent spacing)
  • % - Percentage of parent container (great for widths and heights)
  • vh/vw - Viewport height/width (useful for full-screen sections)
  • Unitless values - For properties like flex, lineHeight

Examples:

// ❌ BAD - Will not scale properly
{
"padding": "20px",
"fontSize": "24px",
"borderRadius": "8px"
}

// βœ… GOOD - Scales seamlessly across all resolutions
{
"padding": "1em",
"fontSize": "1.5em",
"borderRadius": "0.5em"
}

Widget Structure​

Every widget is defined by a JSON object with the following top-level properties:

Core Properties​

PropertyTypeRequiredDescription
namestringβœ…Human-readable widget name
descriptionstring❌Brief description of widget purpose
templateobjectβœ…The root component that renders the widget
options_schemaobject❌Schema defining configurable options
data_schemaobject❌Schema defining dynamic data structure
iconstring❌Widget icon (base64, URL, or emoji)
small_iconstring❌Smaller icon variant
update_interval_secondsnumber❌Auto-refresh interval for dynamic data
metaobject❌Custom metadata for organizational purposes

The Template Object​

The template is the heart of your widget. It defines a tree of components that make up your visual design:

{
"type": "image" | "video" | "text" | "group" | "list" | "image-carousel" | "layout",
"name": string, // Unique identifier for this component
"opts": object, // Component-specific options
"style": CSSProperties, // CSS styling (camelCase or kebab-case)
"animations": array // Optional GSAP animations
}

Component Types​

Castmill provides seven powerful component types that can be composed to create any layout:

1. Image Component​

Display static or dynamic images with customizable sizing and duration.

Type: "image"

Options:

{
url: string | Binding, // Image URL or data binding
size: "cover" | "contain", // How image fills container
duration: number // Display duration in seconds (default: 10)
}

Example (Direct URL):

{
"type": "image",
"name": "hero-image",
"opts": {
"url": "https://example.com/banner.jpg",
"size": "cover",
"duration": 15
},
"style": {
"width": "100%",
"height": "400px",
"borderRadius": "8px"
}
}

Example (Castmill Media with Adaptive Resolution):

{
"type": "image",
"name": "product-photo",
"opts": {
"url": { "key": "options.productImage.files[@target].uri" },
"size": "cover",
"duration": 10
},
"style": {
"width": "100%",
"height": "100%"
}
}
Working with Castmill Media

When using images uploaded to Castmill, use files[@target].uri to automatically get the optimal resolution. See Adaptive Media Resolution for details. ↓

2. Video Component​

Play video content with automatic looping and sizing control.

Type: "video"

Options:

{
url: string | Binding, // Video URL or data binding
size: "cover" | "contain" // Video fit mode
}

Example:

{
"type": "video",
"name": "promo-video",
"opts": {
"url": { "key": "options.video.files[@target].uri" },
"size": "cover"
},
"style": {
"width": "100%",
"height": "100%"
}
}
What's [@target]?

The [@target] variable automatically selects the best video resolution for the contextβ€”preview in the dashboard for fast editing, screen on displays for maximum quality. Castmill generates multiple optimized versions when you upload media. Learn more about adaptive media resolution ↓

3. Text Component​

Render text with automatic sizing, scrolling, and character-level animations.

Type: "text"

Options:

{
text: string | Binding, // Text content or binding
autofit: {
baseSize?: number, // Base font size in em (default: 1)
maxSize?: number, // Maximum font size in em
minSize?: number // Minimum size before enabling scroll
},
chars?: boolean, // Enable character-level animations
perspective?: number // 3D perspective for animations (in pixels)
}

Auto-Fit Behavior:

  • Starts at baseSize
  • Scales up to maxSize if space available
  • Scales down to minSize if text doesn't fit
  • Enables horizontal scrolling if below minSize

Example Code:​

{
"type": "text",
"name": "title",
"opts": {
"text": "Welcome to Castmill",
"autofit": {
"baseSize": 2,
"maxSize": 4,
"minSize": 1
}
},
"style": {
"color": "#ffffff",
"fontWeight": "bold",
"textAlign": "center",
"padding": "1em"
}
}

Live Demo:​

Basic Text Component

A simple text widget with static content and basic styling. This is the foundation for all text-based widgets.

Loading widget player...

Auto-Scroll Behavior​

When text is too long to fit and reaches the minSize, it will automatically scroll horizontally:

Auto-Scrolling Text

Long text that automatically scrolls horizontally when it reaches minimum size. Click play to see the scrolling effect!

Loading widget player...

This example demonstrates:

  • Text is set to maxSize: 4em and minSize: 2em
  • The text is too long to fit at the minimum size, so horizontal scrolling activates when playing
  • 'white-space': 'nowrap' prevents text wrapping, enabling the scroll effect
  • Click the play button to see the text continuously scroll from right to left
  • Perfect for news tickers, announcements, or any content that might overflow

4. Group Component​

Container for multiple components, useful for complex layouts and coordinated animations.

Type: "group"

Important: The components array is a top-level property, not inside opts.

Example Code:​

{
"type": "group",
"name": "header",
"components": [
{
"type": "image",
"name": "logo",
"opts": { "url": "/logo.png", "size": "contain" },
"style": { "width": "10em", "height": "4em" }
},
{
"type": "text",
"name": "tagline",
"opts": { "text": "Digital Signage Made Simple" },
"style": { "marginLeft": "1em", "fontSize": "1.5em" }
}
],
"style": {
"display": "flex",
"alignItems": "center",
"padding": "1em",
"background": "linear-gradient(90deg, #667eea 0%, #764ba2 100%)"
}
}

Live Demo:​

Basic Group Component

A group containing two images arranged side-by-side. Groups are the foundation for building complex layouts with multiple components.

Loading widget player...

5. List Component​

Iterate over data arrays to create repeated elements (menus, schedules, feeds).

Type: "list"

Options:

{
items: Binding, // Data binding to array
itemDuration?: number, // Duration per item (seconds)
itemsPerPage?: number, // Items visible at once
pageDuration?: number, // Duration per page (seconds)
direction?: "horizontal" | "vertical" // Scroll direction
}

Important: The component property (template for each item) is a top-level property, not inside opts.

Example Code:​

{
"type": "list",
"name": "menu-items",
"opts": {
"items": { "key": "data.dishes" },
"itemsPerPage": 5,
"pageDuration": 8
},
"component": {
"type": "group",
"name": "menu-item",
"components": [
{
"type": "text",
"name": "dish-name",
"opts": { "text": { "key": "$.name" } },
"style": { "fontWeight": "bold", "fontSize": "1.8em" }
},
{
"type": "text",
"name": "price",
"opts": { "text": { "key": "$.price" } },
"style": { "fontSize": "1.5em", "color": "#2ecc71" }
}
],
"style": {
"display": "flex",
"justifyContent": "space-between",
"padding": "0.75em 1.5em",
"borderBottom": "0.0625em solid #ecf0f1"
}
}
}

Live Demo - Simple List:​

Basic List Component

A list showing 2 items at a time from 8 total fruits. Pages automatically rotate every 3 seconds when playing. Click play to see the pagination in action!

Loading widget player...

Advanced Example: Dessert Menu Board​

See the list component in action with this elegant dessert menu that combines a background image, styled container, and animated list items:

Dessert Menu Board

An elegant menu board showcasing desserts with names, descriptions, and prices. Items animate in smoothly and paginate automatically every 8 seconds. Watch how 4 items display at once!

Loading widget player...

This example demonstrates several powerful features:

  • Layered components: Background image with overlay content
  • List pagination: Shows 4 items at a time, rotating through all 7 desserts
  • Data binding: Each item pulls name, description, and price from data.desserts
  • Animations: Items slide in from the left with a smooth ease
  • Responsive text: Auto-fitting ensures text scales appropriately
  • Professional styling: Semi-transparent container with border creates depth

Slideshow of multiple images with transition effects.

Type: "image-carousel"

Options:

{
images: string[] | Binding, // Array of image URLs
imageDuration: number // Duration per image (seconds)
}

Example:

{
"type": "image-carousel",
"name": "gallery",
"opts": {
"images": [
"https://example.com/slide1.jpg",
"https://example.com/slide2.jpg",
"https://example.com/slide3.jpg"
],
"imageDuration": 5
},
"style": {
"width": "100%",
"height": "600px"
}
}

7. Layout Component​

Advanced component for multi-zone layouts with independent playlists per zone.

Type: "layout"

Options:

{
containers: Array<{
playlist: Playlist | Binding, // Playlist for this zone
style: CSSProperties // CSS positioning/styling
}>
}

Example (Split-Screen Layout):

{
"type": "layout",
"name": "split-screen",
"opts": {
"containers": [
{
"playlist": { "key": "options.playlists[0]" },
"style": {
"position": "absolute",
"width": "50%",
"height": "100%",
"top": "0",
"left": "0"
}
},
{
"playlist": { "key": "options.playlists[1]" },
"style": {
"position": "absolute",
"width": "50%",
"height": "100%",
"top": "0",
"left": "50%"
}
}
]
},
"style": {
"width": "100%",
"height": "100%",
"position": "relative"
}
}

Data Binding​

Widgets become powerful when connected to dynamic data. Castmill uses a binding system to link template properties to data sources.

Binding Syntax​

Instead of hard-coding values, use binding objects:

{
"key": "path.to.data",
"default": "fallback value" // Optional
}

Data Sources​

There are three data sources you can bind to:

1. Options (options.*)​

Static configuration provided when the widget is added to a playlist:

{
"opts": {
"text": { "key": "options.title" }
}
}

2. Data (data.*)​

Dynamic data fetched from APIs or webhooks:

{
"opts": {
"temperature": { "key": "data.current.temp", "default": "-- Β°C" }
}
}

3. Context ($.*)​

Current iteration context within lists:

{
"type": "list",
"opts": {
"items": { "key": "data.products" },
"component": {
"type": "text",
"opts": { "text": { "key": "$.name" } } // Current product name
}
}
}

Array Access​

Access array elements with bracket notation:

{
"url": { "key": "options.images[0].uri" } // First image
}

Adaptive Media Resolution with [@target]​

Castmill automatically generates multiple versions of uploaded images and videos optimized for different contexts. Instead of hard-coding a specific file, use the [@target] variable for intelligent resolution selection:

{
"type": "image",
"opts": {
"url": { "key": "options.productImage.files[@target].uri" },
"size": "cover"
}
}

How It Works:

When media is uploaded to Castmill, the platform generates multiple optimized versions:

Target KeyPurposeTypical ResolutionUse Case
thumbnailSmall preview~150x150pxLists, grid views
previewMedium preview~480x270pxDashboard editing
screenFull displayOriginal or 1920x1080pxDigital signage screens

The [@target] variable automatically resolves to the appropriate key based on context:

  • Dashboard/Editor: Uses "preview" for faster loading and editing
  • Player on Screens: Uses "screen" for maximum quality
  • Mobile Apps: May use "thumbnail" for bandwidth efficiency

File Structure:

Each media item in Castmill has a files array containing multiple File objects stored in PostgreSQL:

{
"productImage": {
"id": "media_123",
"name": "product-hero.jpg",
"files": [
{ "target": "thumbnail", "uri": "https://cdn.castmill.com/thumb_abc.jpg", "width": 150, "height": 150 },
{ "target": "preview", "uri": "https://cdn.castmill.com/prev_abc.jpg", "width": 480, "height": 270 },
{ "target": "screen", "uri": "https://cdn.castmill.com/screen_abc.jpg", "width": 1920, "height": 1080 }
]
}
}

Benefits:

  • Performance: Dashboard loads quickly with preview-sized media
  • Quality: Screens display full-resolution content
  • Bandwidth: Each context uses appropriately-sized files
  • Automatic: No manual selection neededβ€”Castmill handles it intelligently

Example with Video:

{
"type": "video",
"name": "promo-video",
"opts": {
"url": { "key": "options.video.files[@target].uri" },
"size": "cover"
}
}

This pattern works identically for both images and videos, ensuring optimal media delivery across all Castmill contexts.


Schemas​

Schemas define and validate the data your widget expects.

Options Schema​

Defines configurable parameters for your widget:

{
"options_schema": {
"title": {
"type": "string",
"required": true,
"description": "Main title text"
},
"duration": {
"type": "number",
"default": 10,
"min": 1,
"max": 60,
"description": "Display duration in seconds"
},
"background": {
"type": "string",
"default": "#ffffff",
"description": "Background color (CSS format)"
},
"logo": {
"type": "ref",
"collection": "medias|type:image",
"required": false,
"description": "Company logo"
}
}
}

Field Types​

TypeDescriptionAdditional Attributes
stringText valuedefault, description
numberNumeric valuedefault, min, max, description
booleanTrue/false valuedefault, description
refReference to media/playlistcollection, required, description
mapNested objectschema, required
listArray of itemsitems, required

Data Schema​

Defines the structure of dynamic data:

{
"data_schema": {
"weather": {
"type": "map",
"required": true,
"schema": {
"temperature": "number",
"condition": "string",
"humidity": "number",
"icon": "string"
}
},
"forecast": {
"type": "list",
"items": {
"type": "map",
"schema": {
"day": "string",
"high": "number",
"low": "number",
"icon": "string"
}
}
}
}
}

Animations​

Bring your widgets to life with GSAP-powered animations. Animations use keyframe-based sequences for sophisticated motion.

Animation Structure​

{
"animations": [
{
"init": { // Timeline configuration (optional)
"repeat": -1, // -1 for infinite loop
"yoyo": true // Play animation forward then backward
},
"keyframes": [ // Array of animation steps
{
"set": {}, // Instant property change
"from": {}, // Animate from these values
"to": {} // Animate to these values
}
]
}
]
}

Animation Properties​

All GSAP properties are supported. Common ones:

  • Position: x, y, translateX, translateY
  • Scale: scale, scaleX, scaleY
  • Rotation: rotation, rotateX, rotateY, rotateZ
  • Opacity: opacity, autoAlpha (includes visibility)
  • Timing: duration, delay, ease

Example: Fade In​

{
"animations": [
{
"keyframes": [
{
"set": { "opacity": 0 }
},
{
"to": {
"opacity": 1,
"duration": 1,
"ease": "power2.out"
}
}
]
}
]
}

Example: Slide from Left​

{
"animations": [
{
"keyframes": [
{
"from": {
"x": -200,
"opacity": 0
}
},
{
"to": {
"x": 0,
"opacity": 1,
"duration": 0.8,
"ease": "back.out(1.7)"
}
}
]
}
]
}

Example: Rotating Loop​

{
"animations": [
{
"init": {
"repeat": -1
},
"keyframes": [
{
"to": {
"rotation": 360,
"duration": 4,
"ease": "none"
}
}
]
}
]
}

Example: 3D Flip​

{
"animations": [
{
"init": {
"repeat": -1,
"yoyo": true
},
"keyframes": [
{
"set": {
"rotateY": 0,
"transformOrigin": "50% 50%"
}
},
{
"to": {
"rotateY": 180,
"duration": 2,
"ease": "power2.inOut"
}
}
]
}
]
}

Character-Level Text Animation​

For text components, enable character splitting:

{
"type": "text",
"name": "animated-title",
"opts": {
"text": "Hello World",
"chars": true,
"perspective": 500
},
"animations": [
{
"keyframes": [
{
"from": {
"opacity": 0,
"scale": 0,
"y": -50
}
},
{
"to": {
"opacity": 1,
"scale": 1,
"y": 0,
"duration": 0.3,
"stagger": 0.05, // Delay between each character
"ease": "back.out(2)"
}
}
]
}
]
}

GSAP Easing Functions​

Choose from dozens of easing functions:

  • Power: power1, power2, power3, power4 (with .in, .out, .inOut)
  • Back: back.in, back.out, back.inOut(overshoot)
  • Elastic: elastic.in, elastic.out, elastic.inOut
  • Bounce: bounce.in, bounce.out, bounce.inOut
  • Special: circ, expo, sine, none (linear)

Styling​

Widgets support full CSS styling with both camelCase and kebab-case properties.

Style Properties​

{
"style": {
"width": "100%",
"height": "400px",
"backgroundColor": "#1e3a5f",
"color": "#ffffff",
"padding": "30px",
"borderRadius": "12px",
"boxShadow": "0 4px 6px rgba(0,0,0,0.1)",
"display": "flex",
"flexDirection": "column",
"justifyContent": "center",
"alignItems": "center",
"fontFamily": "'Segoe UI', Tahoma, Geneva, Verdana, sans-serif",
"fontSize": "2em",
"fontWeight": "bold",
"textAlign": "center",
"background": "linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
}
}

Responsive Design​

Use viewport units and flexbox for adaptive layouts:

{
"style": {
"width": "90vw",
"maxWidth": "1200px",
"height": "80vh",
"display": "grid",
"gridTemplateColumns": "repeat(auto-fit, minmax(300px, 1fr))",
"gap": "20px"
}
}

Common Patterns​

Centered Container​

{
"style": {
"display": "flex",
"justifyContent": "center",
"alignItems": "center",
"width": "100%",
"height": "100%"
}
}

Scrolling Text​

{
"style": {
"overflowX": "auto",
"whiteSpace": "nowrap"
}
}

Image Overlay​

{
"style": {
"position": "relative",
"background": "linear-gradient(rgba(0,0,0,0.5), rgba(0,0,0,0.5)), url('image.jpg')",
"backgroundSize": "cover"
}
}

Complete Examples​

Example 1: Restaurant Menu​

Use Case: Elegant menu display with item rotation and smooth transitions.

{
"name": "Restaurant Menu",
"description": "Rotating menu with images and prices",
"update_interval_seconds": 300,
"template": {
"type": "group",
"name": "menu-container",
"opts": {
"components": [
{
"type": "text",
"name": "header",
"opts": {
"text": "Today's Specials",
"autofit": { "baseSize": 3 }
},
"style": {
"textAlign": "center",
"color": "#2c3e50",
"padding": "40px 0",
"fontWeight": "bold",
"borderBottom": "3px solid #e74c3c"
}
},
{
"type": "list",
"name": "menu-list",
"opts": {
"items": { "key": "data.dishes" },
"itemsPerPage": 3,
"pageDuration": 10,
"component": {
"type": "group",
"name": "dish",
"opts": {
"components": [
{
"type": "image",
"name": "dish-image",
"opts": {
"url": { "key": "$.image" },
"size": "cover",
"duration": 10
},
"style": {
"width": "200px",
"height": "200px",
"borderRadius": "12px",
"objectFit": "cover"
}
},
{
"type": "group",
"name": "dish-info",
"opts": {
"components": [
{
"type": "text",
"name": "dish-name",
"opts": {
"text": { "key": "$.name" },
"autofit": { "baseSize": 2 }
},
"style": {
"fontWeight": "bold",
"color": "#2c3e50",
"marginBottom": "10px"
}
},
{
"type": "text",
"name": "description",
"opts": {
"text": { "key": "$.description" }
},
"style": {
"color": "#7f8c8d",
"fontSize": "1.2em",
"lineHeight": "1.4"
}
},
{
"type": "text",
"name": "price",
"opts": {
"text": { "key": "$.price" }
},
"style": {
"fontSize": "2em",
"fontWeight": "bold",
"color": "#27ae60",
"marginTop": "15px"
}
}
]
},
"style": {
"flex": "1",
"padding": "0 30px"
}
}
]
},
"style": {
"display": "flex",
"alignItems": "center",
"padding": "30px",
"borderBottom": "1px solid #ecf0f1"
},
"animations": [
{
"keyframes": [
{
"from": {
"x": 100,
"opacity": 0
}
},
{
"to": {
"x": 0,
"opacity": 1,
"duration": 0.6,
"ease": "power2.out"
}
}
]
}
]
}
},
"style": {
"flex": "1",
"overflow": "hidden"
}
}
]
},
"style": {
"width": "100%",
"height": "100%",
"backgroundColor": "#ffffff",
"display": "flex",
"flexDirection": "column",
"fontFamily": "'Georgia', serif"
}
},
"data_schema": {
"dishes": {
"type": "list",
"items": {
"type": "map",
"schema": {
"name": "string",
"description": "string",
"price": "string",
"image": "string"
}
}
}
}
}

(Continuing with more comprehensive examples in the next parts due to size...)


Best Practices​

1. Design for Readability​

Digital signage is often viewed from a distance:

  • Minimum font size: 18px for body text, 36px+ for headings
  • High contrast: Dark text on light backgrounds or vice versa
  • Limited text: Keep messages concise and scannable
  • Adequate spacing: Use padding and margins generously

2. Optimize Performance​

  • Image sizes: Use appropriately sized images (not larger than display resolution)
  • Animation duration: Keep animations smooth but not too long (0.3-1s for entrances)
  • Update intervals: Don't refresh data more frequently than necessary
  • List pagination: Show 5-10 items per page for optimal readability

3. Handle Missing Data​

Always provide fallbacks:

{
"text": {
"key": "data.temperature",
"default": "-- Β°C"
}
}

4. Test Across Resolutions​

  • Design for your target screen resolution
  • Use viewport units (vw, vh) for responsive sizing
  • Test on actual hardware when possible
  • Consider aspect ratios (16:9, 9:16, 4:3)

5. Organize Complex Widgets​

  • Use group components to organize related elements
  • Give components descriptive names
  • Comment your JSON with additional meta fields if needed
  • Break very complex widgets into multiple simpler ones

6. Leverage Data Binding​

  • Separate content from presentation
  • Use options_schema for static configuration
  • Use data_schema for dynamic, updateable content
  • Validate data with appropriate schemas

7. Animation Guidelines​

  • Entrance animations: 0.5-1 second
  • Exit animations: 0.3-0.5 seconds
  • Looping animations: Subtle and non-distracting
  • Avoid: Excessive movement, flashing, rapid changes

Dynamic Data & Webhooks​

Widgets can fetch dynamic data from external APIs or receive updates via webhooks.

Update Intervals​

Set automatic refresh:

{
"update_interval_seconds": 300 // Refresh every 5 minutes
}

Webhook Integration​

Widgets can receive data pushes from external systems. Configure a webhook URL in your widget:

{
"webhook_url": "widgets/custom-data-handler"
}

Your backend service should send data matching your data_schema to:

POST /api/webhook/widgets/custom-data-handler

Troubleshooting​

Widget Not Displaying​

  1. Check JSON syntax: Validate your JSON (use jsonlint.com)
  2. Verify required fields: Ensure name and template are present
  3. Check bindings: Verify data paths exist in your data source
  4. Review schemas: Ensure data matches data_schema structure

Animations Not Working​

  1. Check component support: Not all properties animate on all components
  2. Verify GSAP properties: Use valid GSAP property names
  3. Test without animations: Confirm component renders correctly first
  4. Check duration: Ensure duration values are reasonable (0.3-3 seconds)

Data Not Updating​

  1. Verify update interval: Check update_interval_seconds is set
  2. Test data source: Ensure API/webhook is responding correctly
  3. Check data format: Validate data matches data_schema
  4. Review network: Confirm player has network connectivity

Performance Issues​

  1. Optimize images: Reduce file sizes and dimensions
  2. Limit animations: Too many simultaneous animations can cause lag
  3. Reduce list size: Show fewer items per page
  4. Simplify nesting: Deeply nested components can impact performance

Resources​

Tools​

Reference​

Component Quick Reference​

ComponentPrimary UseKey Options
imageStatic/dynamic imagesurl, size, duration
videoVideo playbackurl, size
textText displaytext, autofit, chars
groupLayout containercomponents
listData iterationitems, component, itemsPerPage
image-carouselImage slideshowsimages, imageDuration
layoutMulti-zone layoutscontainers

Next Steps​

  1. Start Simple: Create a basic image or text widget
  2. Add Data: Experiment with data bindings and schemas
  3. Enhance with Animations: Add entrance and transition effects
  4. Build Complex Layouts: Combine multiple components
  5. Connect External Data: Set up webhooks or API integrations
  6. Deploy & Test: Upload to Castmill and test on real hardware

Ready to create amazing widgets? Start with the examples above, customize them for your needs, and explore the full potential of Castmill's widget system!


For additional help, consult the Player Documentation, or reach out to the Castmill community.