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:
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β
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β
| Property | Type | Required | Description |
|---|---|---|---|
name | string | β | Human-readable widget name |
description | string | β | Brief description of widget purpose |
template | object | β | The root component that renders the widget |
options_schema | object | β | Schema defining configurable options |
data_schema | object | β | Schema defining dynamic data structure |
icon | string | β | Widget icon (base64, URL, or emoji) |
small_icon | string | β | Smaller icon variant |
update_interval_seconds | number | β | Auto-refresh interval for dynamic data |
meta | object | β | 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%"
}
}
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%"
}
}
[@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
maxSizeif space available - Scales down to
minSizeif 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:β
Auto-Scroll Behaviorβ
When text is too long to fit and reaches the minSize, it will automatically scroll horizontally:
This example demonstrates:
- Text is set to
maxSize: 4emandminSize: 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:β
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:β
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:
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
6. Image Carousel Componentβ
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 Key | Purpose | Typical Resolution | Use Case |
|---|---|---|---|
thumbnail | Small preview | ~150x150px | Lists, grid views |
preview | Medium preview | ~480x270px | Dashboard editing |
screen | Full display | Original or 1920x1080px | Digital 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β
| Type | Description | Additional Attributes |
|---|---|---|
string | Text value | default, description |
number | Numeric value | default, min, max, description |
boolean | True/false value | default, description |
ref | Reference to media/playlist | collection, required, description |
map | Nested object | schema, required |
list | Array of items | items, 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
groupcomponents to organize related elements - Give components descriptive names
- Comment your JSON with additional
metafields if needed - Break very complex widgets into multiple simpler ones
6. Leverage Data Bindingβ
- Separate content from presentation
- Use
options_schemafor static configuration - Use
data_schemafor 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β
- Check JSON syntax: Validate your JSON (use jsonlint.com)
- Verify required fields: Ensure
nameandtemplateare present - Check bindings: Verify data paths exist in your data source
- Review schemas: Ensure data matches
data_schemastructure
Animations Not Workingβ
- Check component support: Not all properties animate on all components
- Verify GSAP properties: Use valid GSAP property names
- Test without animations: Confirm component renders correctly first
- Check duration: Ensure duration values are reasonable (0.3-3 seconds)
Data Not Updatingβ
- Verify update interval: Check
update_interval_secondsis set - Test data source: Ensure API/webhook is responding correctly
- Check data format: Validate data matches
data_schema - Review network: Confirm player has network connectivity
Performance Issuesβ
- Optimize images: Reduce file sizes and dimensions
- Limit animations: Too many simultaneous animations can cause lag
- Reduce list size: Show fewer items per page
- Simplify nesting: Deeply nested components can impact performance
Resourcesβ
Toolsβ
- JSON Validator: https://jsonlint.com
- GSAP Ease Visualizer: https://greensock.com/ease-visualizer
- Color Picker: https://coolors.co
Referenceβ
- GSAP Documentation: https://greensock.com/docs/
- CSS Properties: https://developer.mozilla.org/en-US/docs/Web/CSS
- Flex Guide: https://css-tricks.com/snippets/css/a-guide-to-flexbox/
- Grid Guide: https://css-tricks.com/snippets/css/complete-guide-grid/
Component Quick Referenceβ
| Component | Primary Use | Key Options |
|---|---|---|
image | Static/dynamic images | url, size, duration |
video | Video playback | url, size |
text | Text display | text, autofit, chars |
group | Layout container | components |
list | Data iteration | items, component, itemsPerPage |
image-carousel | Image slideshows | images, imageDuration |
layout | Multi-zone layouts | containers |
Next Stepsβ
- Start Simple: Create a basic image or text widget
- Add Data: Experiment with data bindings and schemas
- Enhance with Animations: Add entrance and transition effects
- Build Complex Layouts: Combine multiple components
- Connect External Data: Set up webhooks or API integrations
- 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.