🚀 Fractal Studio Developer Tutorial

Your Complete Guide to Low-Code Development

1. Introduction to Fractal Studio

What is Fractal Studio?

Fractal Studio is a powerful low-code development platform that combines the flexibility of traditional programming with the speed of visual development. It uses a unique approach where:

Key Components

🗄️ Collections

Like database tables, but stored as JSON files. Each collection can have multiple documents.

📐 Dimensions

Configuration layers that control UI, validation, events, and more without changing code.

🎭 Layouts

HTML templates that define how your data is displayed to users.

⚡ Events

C# methods that respond to user actions like button clicks or form submissions.

✅ Why Fractal Studio?
  • Rapid development - build apps in hours, not weeks
  • Full stack - handles data, UI, and logic
  • AI-powered - automatic generation of code and layouts
  • Version control friendly - all files are text-based

2. Getting Started

Creating Your First Project

When you open Fractal Studio, you'll start with creating a new project:

// The system generates a unique name like "HelloWorld_a1b2c3d4"
var appName = "HelloWorld_a1b2c3d4";

// Project structure is automatically created
Projects/
  FractalPlatform.HelloWorld_a1b2c3d4/
    HelloWorldApplication.cs    // Main code file
    Database/                   // JSON data storage
    Layouts/                    // HTML templates
    Files/                      // Static resources

The Dashboard Interface

Fractal Studio's main interface has three sections:

Section Purpose What You'll Do
App (CSharp/Layouts) Code and UI templates Write C# code, design HTML layouts
Database Data management Create collections, edit JSON documents
Preview Testing See your app in action
💡 Quick Start Tip: Use one of the templates (HelloWorld, TodoList, etc.) to see a working example. Then modify it to learn how things work!

Basic Workflow

  1. Create a collection to store your data
  2. Add dimensions to configure behavior
  3. Design a layout to display the data
  4. Write C# code to handle user interactions
  5. Deploy and test your application

3. Project Structure

File Organization

Every Fractal Studio project follows this structure:

FractalPlatform.YourApp/
├── YourAppApplication.cs          // Main application class
├── Database/
│   ├── Users/                     // Collection name
│   │   ├── Document/
│   │   │   ├── 0000000001.json   // First document
│   │   │   └── 0000000002.json   // Second document
│   │   ├── UI/                   // UI configuration
│   │   │   └── Document/
│   │   │       └── 0000000000.json
│   │   ├── Enum/                 // Dropdown options
│   │   │   └── Document/
│   │   │       └── 0000000000.json
│   │   └── Event/                // Event handlers
│   │       └── Document/
│   │           └── 0000000000.json
│   └── GlobalDimensions/         // Shared configurations
├── Layouts/
│   ├── Users.html                // Main layout
│   └── UsersMobile.html          // Mobile layout
└── Files/
    ├── logo.png                  // Static files
    └── styles.css

Understanding the Main Application File

Your main C# file inherits from DashboardApplication:

public class YourAppApplication : DashboardApplication
{
    // This method runs when app starts
    public override void OnLogin(FormResult result)
    {
        // Initialize your app here
        Dashboard();
    }

    // This method handles user actions
    public override bool OnEventDimension(EventInfo info)
    {
        // Respond to button clicks, form submissions, etc.
        return base.OnEventDimension(info);
    }
}
⚠️ Important: Never manually edit files outside Fractal Studio unless you know what you're doing. The platform manages file structure automatically and expects specific formats.

4. Working with Collections

What is a Collection?

A collection is like a database table, but stored as JSON files. Each collection can have multiple documents (records).

Creating a Collection

In Fractal Studio, click "Add Collection" and fill in the details:

// Collection: "Products"
// First document (0000000001.json):
{
    "Name": "Laptop",
    "Price": 999.99,
    "InStock": true,
    "Categories": ["Electronics", "Computers"]
}

Accessing Collections in Code

Use the built-in methods to query and modify data:

// Get all documents from a collection
var products = DocsOf("Products")
                  .ToCollection();

// Query specific documents
var laptops = DocsWhere("Products", "{'Name':'Laptop'}")
                   .ToCollection();

// Get a single value
var price = DocsWhere("Products", "{'Name':'Laptop'}")
                  .Value("{'Price':$}");
// Returns: "999.99"

// Add a new document
AddDoc("Products", "{'Name':'Mouse','Price':29.99}");

// Update existing documents
ModifyDocsWhere("Products", "{'Name':'Laptop'}")
      .Update("{'Price':899.99}");

// Delete documents
DelDoc("Products", 1); // Delete by ID

Document IDs

Each document has a unique ID stored in its filename:

💡 Pro Tip: Use meaningful collection names (Users, Products, Orders) that match your domain. This makes your code more readable and maintainable.

5. Understanding Dimensions

What are Dimensions?

Dimensions are configuration layers that control various aspects of your application without changing code. Think of them as "settings files" for different behaviors.

Available Dimensions

Dimension Purpose Example Use Case
UI Control appearance and behavior Make fields read-only, set control types
Enum Define dropdown options Status: Active, Inactive, Pending
Event Map UI actions to C# methods Button click → SaveData() method
Validation Define data rules Email must be valid format
Sorting Default sort order Sort products by price ascending
Pagination Configure paging Show 10 items per page

UI Dimension Example

Control how your data is displayed:

{
    "Name": {
        "ReadOnly": false,
        "ControlType": "TextBox",
        "MaxLength": 50
    },
    "Email": {
        "ReadOnly": false,
        "ControlType": "Email"
    },
    "Status": {
        "ControlType": "ComboBox"
    },
    "Bio": {
        "ControlType": "TextArea",
        "Rows": 5
    }
}

Enum Dimension Example

Define dropdown options:

{
    "Status": {
        "Items": ["Active", "Inactive", "Pending"]
    },
    "Country": {
        "Items": ["USA", "Canada", "Mexico"]
    }
}

Setting Dimensions in Code

You can also configure dimensions programmatically:

// Set UI dimension
FirstDocOf("Users")
    .SetUIDimension("{'Name':{'ReadOnly':true}}")
    .OpenForm();

// Set Enum dimension
var countries = new[] { "USA", "Canada", "Mexico" };
FirstDocOf("Users")
    .SetDimension(DimensionType.Enum, 
                  DQL("{'Country':{'Items':[@Countries]}}", countries))
    .OpenForm();
✅ Benefits of Dimensions:
  • Change behavior without modifying code
  • Reuse across different collections
  • Easy to maintain and update
  • Separate concerns (data, logic, presentation)

6. Creating Layouts

What is a Layout?

A layout is an HTML template that defines how your data is displayed. Fractal Studio uses special placeholders that get replaced with actual data.

Basic Layout Structure

div class="form-container"
    

User Profile

div class="field" Name: @Name /div div class="field" Email: @Email /div div class="actions" @Save @Cancel /div /div

Special Placeholders

Placeholder Purpose Example
@FieldName Replaced with input control @Name → text input
@BaseUrl Your app's URL Used for links
@BaseFilesUrl Files directory URL For images, CSS, etc.

AI-Generated Layouts

Fractal Studio can automatically generate modern, responsive layouts:

💡 How to Use AI:
  1. Right-click on the layout area
  2. Select "Design Layout" or "Redesign Layout"
  3. AI analyzes your data structure
  4. Generates professional HTML/CSS

Working with Images and Files


 src="@BaseFilesUrl/logo.png" alt="Logo">


 rel="stylesheet" href="@BaseFilesUrl/styles.css">


 href="@BaseUrl/Products">View Products

Mobile Layouts

Create separate layouts for mobile devices by naming them with "Mobile" suffix:

⚠️ Layout Tips:
  • Keep layouts simple - let dimensions control behavior
  • Test on multiple screen sizes
  • Use semantic HTML for better accessibility
  • Leverage AI generation for complex designs

7. Writing C# Code

Application Class Structure

Your main application class extends DashboardApplication and overrides key methods:

using FractalPlatform.Client.App;
using FractalPlatform.Database.Engine;
using System.Collections.Generic;

namespace FractalPlatform.YourApp
{
    public class YourAppApplication : DashboardApplication
    {
        // Called when user logs in
        public override void OnLogin(FormResult result)
        {
            // Initialize your application
            ShowMainDashboard();
        }

        // Handle user interactions
        public override bool OnEventDimension(EventInfo info)
        {
            switch (info.AttrPath.ToString())
            {
                case "SaveButton":
                    SaveData(info.Collection);
                    return true;
                
                case "DeleteButton":
                    DeleteData(info.Collection);
                    return true;
            }
            
            return base.OnEventDimension(info);
        }
    }
}

Essential Methods for Data Operations

Opening Forms

// Open a form with first document
FirstDocOf("Users")
    .OpenForm(result => 
    {
        if (result.Result)
        {
            // User clicked Save/OK
            var name = result.FindFirstValue("Name");
            MessageBox($"Hello, {name}!");
        }
    });

// Open form with custom object
new 
{
    Name = "",
    Email = "",
    Age = 0
}
.ToCollection("New User")
.OpenForm(result => 
{
    if (result.Result)
    {
        // Save to database
        AddDoc("Users", result.Collection.ToJson());
    }
});

Querying Data

// Get all documents
var allUsers = DocsOf("Users")
                  .ToCollection();

// Filter by condition
var activeUsers = DocsWhere("Users", "{'Status':'Active'}")
                       .ToCollection();

// Get specific document by ID
var user = DocsWhere("Users", 1)
                .ToCollection();

// Count documents
var count = DocsWhere("Users", "{'Status':'Active'}")
                  .Count();

// Get single value
var email = DocsWhere("Users", "{'Name':'John'}")
                  .Value("{'Email':$}");

Modifying Data

// Update documents
ModifyDocsWhere("Users", "{'Name':'John'}")
      .Update("{'Status':'Inactive'}");

// Delete documents
ModifyDocsWhere("Users", "{'Status':'Inactive'}")
      .Delete();

// Add to array
ModifyDocsWhere("Users", "{'Name':'John'}")
      .Update("{'Roles':[Add,'Admin']}");

DQL (Data Query Language)

DQL allows you to pass parameters safely:

// Basic DQL with parameters
var userName = "John";
var user = DocsWhere("Users", DQL("{'Name':@Name}", userName))
                .ToCollection();

// Multiple parameters
var minAge = 18;
var status = "Active";
var users = DocsWhere("Users", 
                        DQL("{'Age':{'>':@MinAge},'Status':@Status}", 
                            minAge, status))
                   .ToCollection();

// Arrays in DQL
var roles = new[] { "Admin", "Manager" };
var dimension = DQL("{'Role':{'Items':[@Roles]}}", roles);

Common UI Helpers

// Show message box
MessageBox("Operation completed!");

// Confirmation dialog
MessageBox("Are you sure?", 
           "Confirm", 
           MessageBoxButtonType.YesNo,
           result => 
           {
               if (result.Result)
               {
                   // User clicked Yes
                   DeleteRecord();
               }
           });

// Input box
InputBox("Enter your name", 
         "User Input",
         result => 
         {
             var name = result.FindFirstValue("Enter your name");
             MessageBox($"Hello, {name}!");
         });
✅ Code Best Practices:
  • Always use DQL for dynamic queries (prevents injection)
  • Handle form results with callbacks
  • Use meaningful variable names
  • Add comments for complex logic

8. Event Handling

Understanding Events

Events connect user actions (button clicks, form submissions) to your C# code. There are several ways to handle events in Fractal Studio.

Method 1: OnEventDimension

The primary method for handling button clicks and other actions:

public override bool OnEventDimension(EventInfo info)
{
    // info.AttrPath contains the path to the clicked element
    var path = info.AttrPath.ToString();
    
    switch (path)
    {
        case "SaveButton":
            // Get data from the form
            var name = info.Collection.FindFirstValue("Name");
            var email = info.Collection.FindFirstValue("Email");
            
            // Save to database
            AddDoc("Users", DQL("{'Name':@Name,'Email':@Email}", 
                                      name, email));
            
            MessageBox("User saved successfully!");
            return true;
        
        case "DeleteButton":
            MessageBox("Are you sure?", 
                       "Confirm Delete",
                       MessageBoxButtonType.YesNo,
                       result => 
                       {
                           if (result.Result)
                           {
                               var id = info.Collection.FindFirstIntValue("ID");
                               DelDoc("Users", id);
                               MessageBox("User deleted!");
                           }
                       });
            return true;
        
        case "RefreshButton":
            ShowUserList();
            return true;
    }
    
    return base.OnEventDimension(info);
}

Method 2: OnOpenForm and OnCloseForm

Handle form lifecycle events:

public override void OnOpenForm(FormResult result)
{
    // Called when a form is about to open
    // Good for initializing data
    
    if (result.Collection.Name == "Users")
    {
        // Pre-fill some data
        result.Collection.SetFirstValue("CreatedDate", 
                                       DateTime.Now.ToString());
    }
    
    base.OnOpenForm(result);
}

public override void OnCloseForm(FormResult result)
{
    // Called when form closes
    // Good for cleanup or validation
    
    if (result.Result && result.Collection.Name == "Users")
    {
        // User clicked Save/OK
        var email = result.FindFirstValue("Email");
        
        if (!email.Contains("@"))
        {
            MessageBox("Invalid email address!");
            return;
        }
    }
    
    base.OnCloseForm(result);
}

Method 3: Event Dimension

Define events in JSON configuration:

// In Event dimension JSON:
{
    "SaveButton": {
        "OnClick": "SaveUser"
    },
    "LoadButton": {
        "OnClick": "LoadUsers"
    }
}

// In your C# code:
public void SaveUser(EventInfo info)
{
    var name = info.Collection.FindFirstValue("Name");
    AddDoc("Users", DQL("{'Name':@Name}", name));
    MessageBox("User saved!");
}

public void LoadUsers(EventInfo info)
{
    var users = DocsOf("Users")
                  .ToCollection();
    
    users.OpenForm();
}

Handling Form Results

// Access form data after submission
FirstDocOf("Users")
    .OpenForm(result => 
    {
        if (result.Result)  // User clicked Save/OK
        {
            // Get single value
            var name = result.FindFirstValue("Name");
            
            // Get typed value
            var age = result.FindFirstIntValue("Age");
            var isActive = result.FindFirstBoolValue("IsActive");
            
            // Get entire collection as JSON
            var json = result.Collection.ToJson();
            
            // Loop through values
            result.Collection.ScanKeysAndValues((attr, value) =>
            {
                Console.WriteLine($"{attr}: {value}");
                return true; // Continue scanning
            });
        }
        else  // User clicked Cancel
        {
            MessageBox("Operation cancelled");
        }
    });

Working with Collections in Events

// Display a list with actions
DocsOf("Users")
    .SetDimension(DimensionType.Patch)
    .OpenForm(result =>
    {
        if (result.Result)
        {
            // Get patch dimension to see changes
            var dimension = (PatchDimension)result.Collection
                                            .GetDimension(DimensionType.Patch);
            
            var patch = dimension.GetPatch();
            
            if (patch.HasChanges)
            {
                // Process deleted items
                patch.DeleteStorage.ToCollection()
                     .ScanKeysAndValues((attr, value) =>
                     {
                         if (attr.LastPath == "ID")
                         {
                             DelDoc("Users", value.IntValue);
                         }
                         return true;
                     });
                
                // Process updated items
                patch.UpdateStorage.ToCollection()
                     .ScanKeysAndValues((attr, value) =>
                     {
                         // Handle updates
                         return true;
                     });
            }
        }
    });
💡 Event Handling Tips:
  • Use switch statements for multiple events
  • Always return true after handling an event
  • Use result.Result to check if user confirmed action
  • Validate data in OnCloseForm before saving

9. Deployment

The Deploy Process

Deployment in Fractal Studio involves compiling your code, uploading files, and creating the database on the server.

Deploy Button

The easiest way to deploy is using the Deploy button in the dashboard:

// What happens when you click "Deploy":

1. Compile C# Code
   - Compiles YourAppApplication.cs
   - Checks for syntax errors
   - Creates assembly DLL

2. Upload Database
   - Uploads all JSON files
   - Creates collections
   - Optionally recreates database

3. Upload Layouts
   - Uploads HTML templates
   - Uploads CSS files
   - Uploads JavaScript files

4. Upload Files
   - Uploads static resources
   - Images, fonts, etc.

5. Register Application
   - Makes app accessible at URL
   - Sets up routing

Deployment Settings

Configure deployment options in Settings:

Setting Description When to Use
IsRecreateDatabase Delete and recreate database When structure changes significantly
IsDeployApplication Upload compiled code When C# code changes
IsDeployLayouts Upload HTML templates When layouts change
IsDeployDatabase Upload JSON data When data structure changes
IsDeployFiles Upload static files When images/CSS change

Deployment Key

The deployment key controls access to your application:

// Default deployment key
var deploymentKey = "sandbox";

// Your app URL structure:
https://fraplat.tech/mars/{YourAppName}

// With URL tag (custom routing):
https://fraplat.tech/mars/{YourAppName}/?tag={YourTag}

Transfer to Another Server

You can transfer your application to different environments:

// Transfer application settings:
{
    "BaseUrl": "https://your-server.com",
    "DeploymentKey": "production",
    "IsDeployApplication": true,
    "IsDeployDatabase": true,
    "IsRecreateDatabase": false, // Keep existing data
    "IsDeployLayouts": true,
    "IsDeployFiles": true
}

Download Project

Download your entire project as a ZIP file:

Pull From Remote

Synchronize your local project with server:

// Pull database from server
PullFromSandbox()  // From main server
PullFromRemote()  // From custom server

// Use cases:
- Team member made changes on server
- Testing with production data
- Recovering lost local changes
- Syncing after manual edits

Preview vs Deploy

Feature Preview Deploy
Speed Instant 10-30 seconds
Compilation No Yes
Layout Only Yes Everything
When to Use Quick UI changes Code or data changes
⚠️ Deployment Warnings:
  • IsRecreateDatabase = true will delete all server data!
  • Always test in sandbox before production
  • Back up important data before major deployments
  • Use different deployment keys for dev/staging/production
✅ Deployment Checklist:
  1. Test locally first (Save & Preview)
  2. Check for compilation errors
  3. Verify database structure is correct
  4. Test layouts on mobile and desktop
  5. Click Deploy and wait for success message
  6. Open in new tab to verify

10. Best Practices

Project Organization

Naming Conventions

// Collections: Use singular nouns
✅ User, Product, Order
❌ Users, Products, Orders

// Layouts: Match collection names
✅ User.html, UserMobile.html
❌ user_form.html, mobile-view.html

// C# Methods: Use PascalCase verbs
✅ SaveUser(), LoadProducts(), DeleteOrder()
❌ save_user(), loadproducts(), delete_order()

// Properties: Use PascalCase nouns
✅ UserName, EmailAddress, OrderTotal
❌ userName, email_address, ordertotal

File Structure

Data Design

JSON Document Structure

// ✅ GOOD: Flat and simple
{
    "Name": "John Doe",
    "Email": "john@example.com",
    "Age": 30,
    "Status": "Active"
}

// ✅ GOOD: Nested when logical
{
    "Name": "John Doe",
    "Address": {
        "Street": "123 Main St",
        "City": "New York",
        "Zip": "10001"
    }
}

// ❌ BAD: Too deeply nested
{
    "User": {
        "Personal": {
            "Name": {
                "First": "John",
                "Last": "Doe"
            }
        }
    }
}

Using Arrays Effectively

// ✅ GOOD: Arrays for lists
{
    "Name": "John Doe",
    "Roles": ["Admin", "User"],
    "Orders": [
        {
            "ID": 1,
            "Total": 99.99,
            "Date": "2024-01-15"
        }
    ]
}

// ✅ GOOD: Add/Remove from arrays
ModifyDocsWhere("Users", "{'Name':'John'}")
      .Update("{'Roles':[Add,'Manager']}");

ModifyDocsWhere("Users", "{'Name':'John'}")
      .Update("{'Roles':[Remove,'User']}");

Code Quality

Error Handling

// ✅ GOOD: Always validate user input
var email = result.FindFirstValue("Email");
if (string.IsNullOrEmpty(email) || !email.Contains("@"))
{
    MessageBox("Please enter a valid email address");
    return;
}

// ✅ GOOD: Check if data exists
var count = DocsWhere("Users", "{'Email':@Email}", email)
                  .Count();

if (count > 0)
{
    MessageBox("Email already exists!");
    return;
}

// ✅ GOOD: Confirm destructive actions
MessageBox("Are you sure you want to delete this user?",
           "Confirm Delete",
           MessageBoxButtonType.YesNo,
           confirmResult =>
           {
               if (confirmResult.Result)
               {
                   DelDoc("Users", userId);
               }
           });

Reusable Code

// ✅ GOOD: Create helper methods
private void ShowUserForm(int? userId = null)
{
    Collection user;
    
    if (userId.HasValue)
    {
        // Edit existing user
        user = DocsWhere("Users", userId.Value)
                   .ToCollection();
    }
    else
    {
        // New user
        user = new { Name = "", Email = "" }
                   .ToCollection("New User");
    }
    
    user.SetUIDimension("{'Style':'Save:Save'}")
        .OpenForm(result =>
        {
            if (result.Result)
            {
                SaveUser(result.Collection, userId);
            }
        });
}

private void SaveUser(Collection data, int? userId)
{
    if (userId.HasValue)
    {
        ModifyDocsWhere("Users", userId.Value)
              .Update(data.ToJson());
    }
    else
    {
        AddDoc("Users", data.ToJson());
    }
    
    MessageBox("User saved successfully!");
    ShowUserList();
}

Performance Tips

Query Optimization

// ❌ BAD: Loading all data unnecessarily
var allUsers = DocsOf("Users").ToCollection();
var activeUsers = new List<User>();
foreach (var user in allUsers)
{
    if (user.Status == "Active")
        activeUsers.Add(user);
}

// ✅ GOOD: Filter in query
var activeUsers = DocsWhere("Users", "{'Status':'Active'}")
                       .ToCollection();

// ✅ GOOD: Use pagination for large datasets
DocsOf("Users")
    .SetDimension(DimensionType.Pagination,
                  "{'Page':{'Size':20}}")
    .OpenForm();

Minimize Form Reopening

// ❌ BAD: Reopening form after every action
public void AddItem()
{
    AddDoc("Items", "{'Name':'New Item'}");
    ShowItemList(); // Reopens entire form
}

// ✅ GOOD: Use Patch dimension for dynamic updates
DocsOf("Items")
    .SetDimension(DimensionType.Patch)
    .OpenForm(result =>
    {
        var dimension = (PatchDimension)result.Collection
                                    .GetDimension(DimensionType.Patch);
        var patch = dimension.GetPatch();
        
        // Process changes without reopening
        ProcessPatch(patch);
    });

UI/UX Best Practices

Form Design

User Feedback

// ✅ GOOD: Confirm actions
AddDoc("Users", userData);
MessageBox("User created successfully!");

// ✅ GOOD: Show errors clearly
if (!IsValidEmail(email))
{
    MessageBox("Invalid email format. Please use: name@domain.com",
               "Validation Error",
               MessageBoxButtonType.Ok);
    return;
}

// ✅ GOOD: Confirm before deletion
MessageBox($"Delete user '{userName}'? This cannot be undone.",
           "Confirm Delete",
           MessageBoxButtonType.YesNo,
           result => { /* handle */ });

Security Considerations

Data Validation

// ✅ GOOD: Always validate on server side
public override void OnCloseForm(FormResult result)
{
    if (result.Result && result.Collection.Name == "Users")
    {
        var email = result.FindFirstValue("Email");
        var age = result.FindFirstIntValue("Age");
        
        // Validate email format
        if (!IsValidEmail(email))
        {
            MessageBox("Invalid email format");
            return;
        }
        
        // Validate age range
        if (age < 18 || age > 120)
        {
            MessageBox("Age must be between 18 and 120");
            return;
        }
    }
}

Use DQL for Dynamic Queries

// ❌ BAD: String concatenation (potential injection)
var userName = userInput;
var query = "{'Name':'" + userName + "'}";
var user = DocsWhere("Users", query);

// ✅ GOOD: Use DQL with parameters
var userName = userInput;
var user = DocsWhere("Users", DQL("{'Name':@UserName}", userName));

Testing Your Application

Test Checklist

  1. Functionality - All buttons and forms work
  2. Validation - Invalid data is rejected
  3. Edge Cases - Empty forms, maximum values
  4. Mobile View - Test on phone-sized screen
  5. Data Integrity - Changes saved correctly
  6. Error Handling - Graceful error messages
  7. Performance - Fast load times

Common Issues and Solutions

Problem Cause Solution
Form doesn't open Collection name misspelled Check exact spelling in Database tab
Data not saving Not calling commit/update Use AddDoc or ModifyDocsWhere
Layout looks wrong CSS not loading Check @ BaseFilesUrl path
Button does nothing Event not handled Add case in OnEventDimension
Compilation error Syntax error in C# Check Deploy logs for details

Debugging Tips

// Show values for debugging
MessageBox($"Debug: Value = {someValue}");

// Log collection contents
var json = myCollection.ToJson();
MessageBox($"Collection: {json}");

// Check if data exists
var count = DocsOf("Users").Count();
MessageBox($"Total users: {count}");

// Verify paths in events
public override bool OnEventDimension(EventInfo info)
{
    MessageBox($"Event path: {info.AttrPath}");
    return base.OnEventDimension(info);
}
✅ Golden Rules:
  • Start Small - Build one feature at a time
  • Test Often - Save and Preview after each change
  • Use AI - Let it generate layouts and dimensions
  • Keep It Simple - Don't over-engineer
  • Leverage Dimensions - Configure, don't code
  • Ask for Help - Join the community on Telegram

Learning Resources

📖 Documentation

Official Wiki - Complete reference for all dimensions and features

💬 Community

Telegram Group - Get help from developers and the creator

🎓 Examples

Study template projects in Fractal Studio - HelloWorld, TodoList, etc.

🔧 Transactions Guide

Learn database operations and data consistency from the transactions documentation

Next Steps

  1. Create Your First App
    • Start with HelloWorld template
    • Add a simple collection (e.g., Tasks)
    • Create a basic form
    • Deploy and test
  2. Explore Dimensions
    • Try different UI controls
    • Add validation rules
    • Experiment with layouts
  3. Build Something Real
    • Choose a simple project
    • Plan your collections
    • Implement features incrementally
    • Get feedback from users
  4. Join the Community
    • Share your projects
    • Ask questions
    • Help other beginners
    • Stay updated on new features