Lightning.js - Documentation

Getting Started

Installation

Lightning.js can be installed using npm or yarn. Open your terminal and navigate to your project directory. Then, run the following command:

npm install lightningjs
# or
yarn add lightningjs

This will install Lightning.js and its dependencies. You’ll also need a bundler like Webpack or Parcel to handle the module imports. Refer to the bundler’s documentation for specific setup instructions.

Creating your first Lightning.js app

Let’s create a simple “Hello, world!” application. First, create an HTML file (e.g., index.html):

<!DOCTYPE html>
<html>
<head>
  <title>My Lightning.js App</title>
</head>
<body>
  <script src="./app.js"></script> </body>
</html>

Next, create a JavaScript file (app.js) containing your Lightning.js code:

import { Lightning } from 'lightningjs';

class MyComponent extends Lightning.Component {
  static _template() {
    return {
      text: {
        text: {text: 'Hello, world!'}
      }
    };
  }
}

class MyApplication extends Lightning.Application {
  static _template() {
    return {
      MyComponent: { type: MyComponent }
    };
  }
}

const app = new MyApplication({
  stage: {
    w: 1920,
    h: 1080,
    backgroundColor: 0x000000
  }
});

app.start();

This code defines a simple component that displays “Hello, world!” and an application that uses this component. Remember to adjust the stage dimensions (w and h) to match your desired screen resolution.

Basic Project Structure

A typical Lightning.js project might have the following structure:

my-lightning-app/
├── index.html
├── app.js          // Main application entry point
├── components/     // Directory for reusable components
│   ├── MyComponent.js
│   └── AnotherComponent.js
├── styles/        // (Optional) Directory for CSS or styled-components
│   └── styles.css
└── ...             // Other assets (images, fonts, etc.)

Organize your code into components for better maintainability and reusability. Keep your CSS or styling separate from your component logic where appropriate.

Running your app

Once you’ve created your index.html and app.js files, and configured your bundler, you can run your application by opening index.html in a web browser. The browser should render your Lightning.js application. If you are using a bundler, you might need to run the bundler first to create the necessary output files. Consult your bundler’s documentation for details on how to run the development server. For example, with Webpack you might use a command like npm start (depending on your package.json configuration).

Core Concepts

The Stage

The Stage in Lightning.js is the root of the visual hierarchy. It represents the entire screen area where your application’s content is rendered. Think of it as the canvas onto which all your visual elements are drawn. It manages the rendering process and provides properties like width (w), height (h), and background color (backgroundColor). The stage is a single instance within a given application. You define its dimensions when you create your application instance. All components and actors within your application are ultimately children of the stage.

Scenes and Transitions

Scenes are containers for groups of Actors or Components. They provide a way to organize your application’s UI into logical units, such as a menu screen, a game level, or a settings screen. Switching between scenes is managed through transitions, which can add visual flair and enhance the user experience. Lightning.js offers built-in transition types (like fade, zoom, etc.), or you can create custom transitions to fit your app’s style. A scene manages the lifecycle of its children; components within a scene are created, updated and destroyed along with the scene itself.

Actors and Components

Actors and Components are the building blocks of your Lightning.js application’s UI. Both are visual elements that can be added to the stage or to scenes. The key difference lies in their functionality:

Events and Event Handling

Lightning.js uses an event system for handling user interactions and application state changes. Components and Actors can emit events, and you can attach listeners to handle these events. Common events include mouse clicks, key presses, touch gestures, and custom application events. Event handling is crucial for building interactive and responsive applications. Lightning.js’s event system allows for event bubbling, enabling handling of events at multiple levels in the component hierarchy.

State Management

Effective state management is essential for building complex applications. Lightning.js doesn’t enforce a specific state management pattern but provides tools to handle state within components. You can manage state directly within component properties, using simpler approaches for smaller applications, or employ more sophisticated techniques like Flux, Redux, or custom solutions for larger, more complex projects. Lightning.js’s component lifecycle methods (_setup, _active, _inactive, _cleanup) provide key points for managing state changes in response to component activation and deactivation.

Data Binding

Data binding simplifies the process of synchronizing data between your application’s model and your UI. Lightning.js supports data binding through its templating system. Changes to your data model automatically update the corresponding UI elements, and vice versa, reducing the need for manual updates and improving code maintainability.

Templates

Templates are used to define the structure and content of components. They provide a declarative way to specify the visual hierarchy and properties of a component using a JSON-like structure. Templates separate the structure of your UI from the component’s logic, promoting code readability and making it easier to modify the UI without affecting the underlying functionality. They significantly improve the maintainability of complex UIs.

Actors and Components

Creating custom actors

Creating a custom actor involves extending the Lightning.Actor class and overriding methods to define its behavior and rendering. Here’s a basic example:

import { Lightning, Actor } from 'lightningjs';

class MyCustomActor extends Actor {
  static get _template() {
    return {}; //No template needed for this basic example
  }

  constructor(...args){
    super(...args);
    this.color = 0xff0000; // Red color
  }

  draw(ctx) {
    ctx.fillStyle = '#' + this.color.toString(16);
    ctx.fillRect(0, 0, this.w, this.h);
  }

  _handleUp() {
    this.color = this.color === 0xff0000 ? 0x0000ff : 0xff0000; //Toggle color on click
    this.stage.nextFrame(() => this.draw()); //Request redraw
  }
}

export default MyCustomActor;

This actor draws a colored rectangle. The draw method performs the actual rendering using the provided CanvasRenderingContext2D (ctx). _handleUp() demonstrates handling an event. Note the use of this.stage.nextFrame() to efficiently schedule redraws. Remember to adjust the _handleUp() method to trigger on the appropriate event based on your application’s interaction methods.

Component lifecycle

Components in Lightning.js have a well-defined lifecycle, providing hooks for managing resources and state changes. Key lifecycle methods include:

Understanding these lifecycle methods is crucial for optimizing performance and managing component state effectively.

Using built-in components

Lightning.js provides several built-in components that simplify development. Examples include:

These components handle many aspects of rendering and interaction for you, improving development speed and efficiency. Consult the Lightning.js API documentation for a complete list of built-in components and their options.

Component Composition

Component composition is a powerful technique for creating reusable and well-structured UIs. It involves nesting components within each other, creating hierarchical structures that represent the UI’s layout and functionality. This promotes modularity and improves maintainability. For example, you could create a Button component and reuse it multiple times in various other components (like a SettingsMenu or Dialog).

Rendering Performance

Optimizing rendering performance is crucial for a smooth user experience, especially on resource-constrained devices. Here are some key considerations:

By following these guidelines, you can ensure that your Lightning.js application performs optimally, providing a fluid and responsive user interface.

UI Components

Text

The Lightning.Text component renders text on the screen. Key properties include:

Example:

import { Lightning, Text } from 'lightningjs';

class MyComponent extends Lightning.Component {
  static _template() {
    return {
      myText: { type: Text, text: "Hello, Lightning.js!", fontSize: 32, textColor: 0xffffff }
    };
  }
}

Images

The Lightning.Image component displays images. Key properties include:

Lightning.js handles image loading and caching efficiently. Ensure that your images are optimized for size and format.

Example:

import { Lightning, Image } from 'lightningjs';

class MyComponent extends Lightning.Component {
  static _template() {
    return {
      myImage: { type: Image, src: "myImage.png", x: 100, y: 100 }
    };
  }
}

Buttons

While Lightning.js doesn’t provide a dedicated “Button” component out-of-the-box, you can easily create one using a Lightning.Rectangle or other visual elements combined with event handling. You’d typically style a rectangle to look like a button and add an _handleUp (or other relevant event handler) to trigger an action when clicked.

Example (using Rectangle):

import { Lightning, Rectangle } from 'lightningjs';

class MyButton extends Lightning.Component {
  static _template() {
    return {
      rect: { type: Rectangle, color: 0x008000, w: 150, h: 50, smooth: true } //Green rectangle
    }
  }

  _handleUp() {
    this.fireAncestors('buttonClicked', { buttonId: this.id });
  }
}

This example creates a green button. The _handleUp method fires a custom event buttonClicked up the component tree, allowing parent components to handle the button press.

Lists

Lightning.js doesn’t include a ready-made list component, but you can create one using a combination of other components such as Lightning.Component, Lightning.Text, and potentially a scrolling container if the list is long. You’d create an array to store your list data, then dynamically create and render the list items using this data. This requires more manual implementation but allows for greater control over the list’s appearance and behavior.

Input Fields

Similar to lists and buttons, Lightning.js does not offer a pre-built input field component. You would need to implement this using a combination of components (e.g., Lightning.Text for displaying the input and potentially Lightning.Rectangle for visual boundaries) and handling keyboard input events to manage the text entry process. This necessitates custom handling of keyboard events and managing the internal text state within your component.

Containers

Containers are fundamental for structuring your UI. While not a specific built-in component type, you can create containers using Lightning.Component and arrange child components within their _template. These containers are essential for organizing and laying out your UI elements. They handle positioning and sizing of their children.

Customizing Components

You can customize the appearance and behavior of existing components (e.g., Lightning.Text, Lightning.Image) using CSS, styling properties directly within the component’s template, or by extending the existing component class and overriding methods. Using styling properties and extending the component classes provide more control and allow for more complex customizations. Use CSS for simpler styling tasks if your bundler integrates it appropriately with Lightning.js.

Styling and theming

Using CSS

While Lightning.js is primarily a JavaScript-based framework, you can integrate CSS for styling in many cases, depending on your bundling setup. This allows for a more familiar styling approach for developers comfortable with CSS. However, note that direct DOM manipulation is generally avoided in Lightning.js, and CSS integration might not be fully supported depending on your bundler and build process. Consult the documentation for your chosen bundler (Webpack, Parcel, etc.) and see if it offers integration options to allow CSS styling of Lightning.js components.

Theming with Lightning.js

Lightning.js facilitates theming through the use of component properties and data binding. Instead of relying solely on CSS, you create theme objects that contain style configurations (colors, font sizes, etc.). These theme objects can then be applied to your components either directly or through data binding. This approach maintains the separation of concerns between presentation and logic that is central to Lightning.js’s design.

Example:

const myTheme = {
  backgroundColor: 0x222222,
  textColor: 0xffffff,
  fontSize: 24,
};

class MyComponent extends Lightning.Component {
  static _template() {
    return {
      text: { type: Text, text: {bind:"$text"}, textColor: {bind: '$theme.textColor'}, fontSize: {bind: '$theme.fontSize'}}
    };
  }

  get $text() {
     return "Hello, themed world!";
  }

  set theme(value){
    this.tag("text").patch({text: value.text});
    this.tag("text").setSmooth(true)
    this._theme = value
    this.patch({theme: value});
  }
}

const myComponent = new MyComponent({theme: myTheme});

Custom Themes

To create custom themes, simply define JavaScript objects containing the desired style properties. These objects can then be passed to your components as data, allowing you to easily switch between themes by changing the data passed to the components. This approach ensures a clean separation of theme data from the component’s logic. You could even load themes from external JSON files or other data sources.

Responsive design

Lightning.js offers flexibility for creating responsive designs. You can use the stage dimensions (this.w, this.h) and component properties (like x, y, w, h) within your component’s logic to dynamically adjust the layout based on the available screen size. For more complex responsive layouts, consider using a dedicated layout management system in conjunction with Lightning.js. You could leverage the component lifecycle methods and events to recalculate and update the layout when the stage dimensions change, ensuring your application adapts to different screen sizes and orientations effectively. You could also define different themes optimized for different screen sizes.

Advanced Techniques

Animations

Lightning.js doesn’t have a dedicated animation library built-in, but it provides the necessary tools to create animations efficiently. The primary method is to use this.stage.nextFrame() to schedule updates to component properties over time. This creates smooth animations by repeatedly changing properties (like x, y, alpha, scale, etc.) within a loop, re-rendering the component on each frame. You can create complex animations by combining this technique with easing functions (which you’ll likely implement yourself or use from a third-party library).

Example (simple fade-in animation):

class MyComponent extends Lightning.Component {
  _active() {
    this.alpha = 0; //Start transparent
    this._animateIn();
  }

  _animateIn() {
    if (this.alpha < 1) {
      this.alpha += 0.05;
      this.stage.nextFrame(this._animateIn.bind(this)); //Recursive call
    }
  }
}

For more complex animations, consider using a dedicated animation library (like GSAP or Anime.js), but remember to handle their integration with the Lightning.js rendering cycle to avoid conflicts.

Working with external libraries

Integrating external libraries often involves using your bundler (Webpack, Parcel, etc.) to manage dependencies and module imports. The process depends significantly on the library’s design:

Testing

Testing in Lightning.js typically involves unit and integration tests. You’ll use testing frameworks like Jest, Mocha, or Jasmine. Focus on testing the component logic separately from the rendering aspects. Testing the visual rendering aspects directly is more challenging and usually requires more advanced techniques or tools that capture screenshots for visual comparison. Mocking component interactions and dependencies is also important for writing effective unit tests.

Debugging

Debugging Lightning.js applications often relies on the browser’s developer tools. Use the console to log values, inspect component properties, and track errors. The browser’s debugger can be used to step through your code and identify problematic areas. For complex debugging scenarios, logging key events and state changes can significantly aid in pinpointing the root causes of issues.

Performance Optimization

Optimizing Lightning.js application performance involves techniques mentioned earlier: minimizing redraws using this.stage.nextFrame(), using efficient data structures, and avoiding unnecessary calculations. Profiling your application using browser developer tools can help identify performance bottlenecks. Additionally, consider optimizing image assets and simplifying your component hierarchy to reduce the overall rendering load.

Accessibility

Building accessible applications requires careful consideration of various factors. For Lightning.js applications:

Remember that accessibility is an ongoing process, and thorough testing with assistive technologies is crucial to ensure inclusivity.

Deployment

Web Deployment

Deploying a Lightning.js application to the web is relatively straightforward. After building your application using your chosen bundler (Webpack, Parcel, Rollup, etc.), you’ll have a set of optimized JavaScript and asset files. These files, along with your index.html file, can be deployed to any web hosting service that supports static file hosting. The process is similar to deploying any other static website. Ensure that your web server correctly serves the necessary files and handles appropriate caching mechanisms for optimal performance. You might also consider using a CDN (Content Delivery Network) to improve loading times for users in different geographical locations.

Mobile Deployment (iOS and Android)

Deploying to mobile platforms (iOS and Android) typically requires using a native container technology like Cordova, Capacitor, or React Native. These frameworks allow you to embed your Lightning.js application within a native mobile application shell, giving you access to native device features while still leveraging the performance and capabilities of Lightning.js for your UI. You’ll need to follow the specific instructions provided by the chosen framework. This usually involves setting up build configurations, configuring plugins (for accessing device features like camera or geolocation), and managing the application lifecycle within the native container. The process involves building your Lightning.js app and then integrating it into the native mobile project.

Building for different platforms

Building your Lightning.js application for different platforms primarily involves configuring your bundler and potentially using platform-specific plugins or libraries. For web deployment, your bundler likely handles optimization based on target browsers. Mobile deployment requires handling any platform-specific code or configuration within your native container technology (Cordova, Capacitor, etc.). This might involve conditional code based on platform detection, using platform-specific plugins, or configuring different build settings for iOS and Android. If you need to support older browsers or specific mobile devices, you may need to make adjustments to your build process or codebase to ensure compatibility. Thorough testing on target devices and browsers is critical for a successful multi-platform deployment.

API Reference

This section provides a high-level overview. For detailed and up-to-date information, always refer to the official Lightning.js API documentation. The specific methods and properties available might change between versions.

Stage API

The Stage API provides methods for managing the application’s rendering surface. Key methods and properties typically include:

This is not an exhaustive list; consult the official documentation for all available methods and their detailed descriptions.

Scene API

The Scene API allows managing scenes within the application. Expect methods related to:

Actor API

The Actor API provides the fundamental building blocks for visual elements. Typical methods include:

Component API

The Component API extends the Actor API with additional functionality for managing state, data binding, and templating. Expect methods and properties related to:

Utility functions

Lightning.js often provides utility functions to assist with common tasks. These can include:

The specific utility functions vary depending on the version of the library. Consult the official documentation for a comprehensive list.

Remember: This is a high-level overview. Always check the official Lightning.js API documentation for the most accurate and up-to-date information.

Troubleshooting

Common Issues and Solutions

This section addresses some frequently encountered problems when developing with Lightning.js. Remember to always check the browser’s developer console for specific error messages.

Error Messages

Lightning.js will output error messages to the browser’s developer console. These messages provide crucial information about the nature and location of problems. Pay close attention to the error messages; they typically indicate the file and line number where the error occurred, providing a starting point for debugging. Common error messages might include:

Community Support

For additional assistance, consider the following resources:

Remember to provide as much detail as possible when seeking help, including your code, the steps to reproduce the problem, and any relevant error messages. This helps community members or support teams diagnose and resolve your issue efficiently.