Build the Animated SAC Bootloader

A copy-and-build guide: create the widgets, paste the CSS, add three variables, add two timers, and paste the scripts.

1. What you are building

  • 32 animated panels arranged in a 4 × 8 grid.
  • Terminal-style loading text and boot log.
  • Heartbeat system status indicator.
  • Animated progress bar and percentage.
  • 42-frame sequence driven by Timer_1.
  • Final state: DASHBOARD READY, SYSTEM ONLINE, and the closing message.

How it works

Timer_2 resets the loader. Timer_1 advances RainStep from 0 to 41. Each RainStep swaps CSS classes on the panels and text widgets. The CSS provides the glow, flash, trace, powered and final visual states.

2. Create these SAC objects

TypeExact IDPurpose
PanelPanel_1 to Panel_324 × 8 animated grid
PanelPanel_ProgressTrackProgress bar track
PanelPanel_ProgressFillAnimated progress fill
TextText_LoadingMain loading message
TextText_ProgressPercentage value
TextText_StatusHeartbeat / online status
TextText_BootLogBoot sequence messages
TextText_RememberFinal message
TimerTimer_1Animation engine
TimerTimer_2Reset/start timer

Use the IDs exactly as shown. The scripts reference them directly.

3. Build the layout

  1. Place Panel_1 to Panel_32 in a 4-row × 8-column grid.
  2. Keep all 32 panels the same size with even spacing.
  3. Place Text_Loading below the grid and centre it.
  4. Create Panel_ProgressTrack below Text_Loading.
  5. Place Panel_ProgressFill inside/over the progress track, aligned left.
  6. Place Text_Progress over or beside the progress bar.
  7. Place Text_Status and Text_BootLog in the boot-log area.
  8. Place Text_Remember where the final message should appear. It will be hidden during boot.

4. Create the script variables

IDTypeDefaultArray
BootLogstring“”No
RainRunningbooleanfalseNo
RainStepinteger0No

Do not expose any of these as URL parameters.

5. Add the CSS

Open the story/application CSS editor and paste the complete CSS below. These classes are the visual engine for the animation.

/* ===================================================== */
/* BOOT SEQUENCE LOG                                     */
/* ===================================================== */

.boot-log .sap-custom-text-widget {
    background-color: transparent;
    border: none;
    opacity: 1;
}

.boot-log .sap-custom-text {
    color: rgba(80, 205, 180, 0.72);
    font-family: monospace;
    font-size: 14px;
    font-weight: normal;
}


/* Final completed boot log */

.boot-log-ready .sap-custom-text-widget {
    background-color: transparent;
    border: none;
    opacity: 1;
}

.boot-log-ready .sap-custom-text {
    color: rgba(120, 255, 210, 0.88);
    font-family: monospace;
    font-size: 14px;
    font-weight: normal;
}


.remember-message .sap-custom-text-widget {
  
    border: none;
}

.remember-message .sap-custom-text {
    color: rgba(120,255,210,0.95);
    font-size: 22px;
    font-weight: 700;
  
}



/* ===================================================== */
/* PROGRESS BAR                                          */
/* ===================================================== */

.progress-track .sap-custom-panel-widget {
    background-color: rgba(2, 22, 25, 0.96);
    border: 1px solid rgba(0, 175, 150, 0.45);
    opacity: 1;
    border-radius: 6px;

    box-shadow:
        inset 0px 0px 12px rgba(0, 0, 0, 0.65),
        0px 0px 10px rgba(0, 180, 155, 0.20);
}

.progress-fill .sap-custom-panel-widget {
    background-color: rgba(0, 220, 185, 1);
    border: 1px solid rgba(210, 255, 242, 1);
    opacity: 1;
    border-radius: 5px;

    box-shadow:
        inset 0px 0px 10px rgba(255, 255, 255, 0.30),
        0px 0px 12px rgba(0, 255, 215, 0.95),
        0px 0px 28px rgba(0, 220, 190, 0.65);
}

.progress-fill-flash .sap-custom-panel-widget {
    background-color: rgba(220, 255, 245, 1);
    border: 1px solid rgba(255, 255, 255, 1);
    opacity: 1;
    border-radius: 5px;

    box-shadow:
        0px 0px 15px rgba(255, 255, 255, 1),
        0px 0px 36px rgba(0, 255, 215, 1);
}

.progress-fill-ready .sap-custom-panel-widget {
    background-color: rgba(60, 235, 180, 1);
    border: 1px solid rgba(220, 255, 240, 1);
    opacity: 1;
    border-radius: 5px;

    box-shadow:
        inset 0px 0px 8px rgba(255, 255, 255, 0.25),
        0px 0px 14px rgba(0, 255, 190, 0.85);
}




/* ===================================================== */
/* HEARTBEAT STATUS                                      */
/* ===================================================== */

.heartbeat-on .sap-custom-text {
    color: rgba(120,255,210,1);
    font-family: monospace;
    font-size: 13px;
    font-weight: bold;
}

.heartbeat-on .sap-custom-text-widget {
    background-color: transparent;
    opacity: 1;
}


.heartbeat-off .sap-custom-text {
    color: rgba(40,120,105,0.45);
    font-family: monospace;
    font-size: 13px;
    font-weight: bold;
}

.heartbeat-off .sap-custom-text-widget {
    background-color: transparent;
    opacity: 1;
}





/* ===================================================== */
/* DASHBOARD LOADING TEXT                                */
/* ===================================================== */


/* —————————————————– */
/* Idle                                                  */
/* —————————————————– */

.loading-text-idle .sap-custom-text-widget {
    background-color: rgba(3, 28, 30, 0.92);
    border: 1px solid rgba(0, 175, 150, 0.55);
    opacity: 0.85;
    border-radius: 8px;

    box-shadow:
        inset 0px 0px 18px rgba(0, 125, 110, 0.18),
        0px 0px 10px rgba(0, 180, 155, 0.25);
}

.loading-text-idle .sap-custom-text {
    color: rgba(80, 210, 185, 0.75);
    font-family: monospace;
    font-size: 18px;
    font-weight: bold;
}


/* —————————————————– */
/* Active                                                */
/* —————————————————– */

.loading-text-active .sap-custom-text-widget {
    background-color: rgba(0, 65, 60, 0.96);
    border: 2px solid rgba(120, 255, 220, 0.9);
    opacity: 1;
    border-radius: 8px;

    box-shadow:
        inset 0px 0px 20px rgba(160, 255, 230, 0.18),
        0px 0px 14px rgba(0, 255, 210, 0.75),
        0px 0px 32px rgba(0, 220, 185, 0.38);
}

.loading-text-active .sap-custom-text {
    color: rgba(205, 255, 240, 1);
    font-family: monospace;
    font-size: 18px;
    font-weight: bold;
}


/* —————————————————– */
/* Flash                                                 */
/* —————————————————– */

.loading-text-flash .sap-custom-text-widget {
    background-color: rgba(180, 255, 230, 1);
    border: 2px solid rgba(255, 255, 255, 1);
    opacity: 1;
    border-radius: 8px;

    box-shadow:
        0px 0px 16px rgba(255, 255, 255, 1),
        0px 0px 40px rgba(0, 255, 215, 0.95);
}

.loading-text-flash .sap-custom-text {
    color: rgba(0, 55, 48, 1);
    font-family: monospace;
    font-size: 18px;
    font-weight: bold;
}


/* —————————————————– */
/* Ready                                                 */
/* —————————————————– */

.loading-text-ready .sap-custom-text-widget {
    background-color: rgba(5, 78, 66, 0.98);
    border: 2px solid rgba(145, 255, 215, 1);
    opacity: 1;
    border-radius: 8px;

    box-shadow:
        inset 0px 0px 16px rgba(150, 255, 225, 0.2),
        0px 0px 18px rgba(0, 255, 200, 0.7);
}

.loading-text-ready .sap-custom-text {
    color: rgba(225, 255, 245, 1);
    font-family: monospace;
    font-size: 18px;
    font-weight: bold;
}


/* ===================================================== */
/* DIGITAL RAIN — PANEL STATES                           */
/* ===================================================== */


/* —————————————————– */
/* Amber processing state                                */
/* —————————————————– */

.rain-process .sap-custom-panel-widget {
    background-color: rgba(185, 110, 0, 0.96);
    border: 2px solid rgba(255, 220, 145, 1);
    opacity: 1;

    box-shadow:
        inset 0px 0px 20px rgba(255, 245, 205, 0.35),
        0px 0px 12px rgba(255, 185, 60, 0.9),
        0px 0px 30px rgba(255, 145, 0, 0.55);
}


/* —————————————————– */
/* Deliberate digital glitch                             */
/* —————————————————– */

.rain-glitch .sap-custom-panel-widget {
    background-color: rgba(0, 210, 185, 0.95);

    border-top: 3px solid rgba(255, 255, 255, 1);
    border-right: 2px dashed rgba(0, 255, 220, 0.9);
    border-bottom: 3px dotted rgba(0, 100, 90, 0.9);
    border-left: 2px solid rgba(255, 255, 255, 0.8);

    opacity: 0.78;

    box-shadow:
        inset 8px 0px 0px rgba(255, 255, 255, 0.25),
        -5px 0px 0px rgba(0, 255, 215, 0.35),
        5px 0px 0px rgba(255, 180, 0, 0.25);
}


/* —————————————————– */
/* Dormant panel                                         */
/* —————————————————– */

.rain-dormant .sap-custom-panel-widget {
    background-color: rgba(5, 18, 24, 0.92);
    border: 1px solid rgba(50, 95, 105, 0.35);
    opacity: 0.82;

    box-shadow:
        inset 3px 3px 8px rgba(0, 0, 0, 0.55),
        inset -3px -3px 8px rgba(70, 140, 150, 0.08);
}


/* —————————————————– */
/* Previously activated panel                            */
/* —————————————————– */

.rain-trace .sap-custom-panel-widget {
    background-color: rgba(4, 45, 50, 0.92);
    border: 1px solid rgba(45, 180, 165, 0.48);
    opacity: 0.92;

    box-shadow:
        inset 0px 0px 18px rgba(0, 160, 145, 0.18),
        0px 0px 8px rgba(0, 180, 160, 0.28);
}


/* —————————————————– */
/* Bright active panel                                   */
/* —————————————————– */

.rain-active .sap-custom-panel-widget {
    background-color: rgba(0, 180, 155, 0.96);
    border: 2px solid rgba(195, 255, 235, 1);
    opacity: 1;

    box-shadow:
        inset 0px 0px 22px rgba(230, 255, 248, 0.42),
        0px 0px 12px rgba(0, 255, 210, 0.95),
        0px 0px 30px rgba(0, 220, 190, 0.70);
}


/* —————————————————– */
/* White-hot flash                                       */
/* —————————————————– */

.rain-flash .sap-custom-panel-widget {
    background-color: rgba(220, 255, 245, 1);
    border: 3px solid rgba(255, 255, 255, 1);
    opacity: 1;

    box-shadow:
        inset 0px 0px 18px rgba(255, 255, 255, 0.9),
        0px 0px 16px rgba(255, 255, 255, 1),
        0px 0px 42px rgba(0, 255, 215, 1);
}


/* —————————————————– */
/* Fully powered panel                                   */
/* —————————————————– */

.rain-powered .sap-custom-panel-widget {
    background-color: rgba(8, 72, 78, 0.96);
    border: 1px solid rgba(75, 230, 210, 0.72);
    opacity: 1;

    box-shadow:
        inset 3px 3px 10px rgba(0, 0, 0, 0.35),
        inset -3px -3px 10px rgba(130, 255, 230, 0.14),
        0px 0px 12px rgba(0, 210, 185, 0.35);
}


/* —————————————————– */
/* Final polished dashboard card                         */
/* —————————————————– */

.rain-final .sap-custom-panel-widget {
    background-color: rgba(242, 249, 248, 0.98);
    border: 1px solid rgba(0, 120, 120, 0.28);
    opacity: 1;

    box-shadow:
        inset 0px 4px 0px rgba(0, 175, 155, 0.75),
        4px 6px 14px rgba(0, 35, 40, 0.16);
}


/* ===================================================== */
/* CENTRAL CORE                                          */
/* ===================================================== */


/* —————————————————– */
/* Core idle                                             */
/* —————————————————– */

.rain-core-idle .sap-custom-shape-widget {
    background-color: rgba(4, 18, 24, 1);
    border: 2px solid rgba(0, 140, 135, 0.55);

    box-shadow:
        inset 0px 0px 18px rgba(0, 100, 100, 0.3),
        0px 0px 12px rgba(0, 150, 145, 0.32);
}


/* —————————————————– */
/* Core active                                           */
/* —————————————————– */

.rain-core-active .sap-custom-shape-widget {
    background-color: rgba(0, 190, 165, 1);
    border: 3px solid rgba(215, 255, 245, 1);

    box-shadow:
        inset 0px 0px 20px rgba(255, 255, 255, 0.45),
        0px 0px 18px rgba(255, 255, 255, 0.85),
        0px 0px 50px rgba(0, 255, 215, 0.95);
}


/* —————————————————– */
/* Core flash                                            */
/* —————————————————– */

.rain-core-flash .sap-custom-shape-widget {
    background-color: rgba(245, 255, 252, 1);
    border: 4px solid rgba(255, 255, 255, 1);

    box-shadow:
        0px 0px 25px rgba(255, 255, 255, 1),
        0px 0px 65px rgba(0, 255, 220, 1);
}

6. Page_1 — onInitialization

Add this single line to Page_1 → onInitialization:

Timer_2.start(1);

7. Timer_2 — reset and start

Paste the following into Timer_2. This resets every visual state and then starts Timer_1.

Timer_1.stop();

RainStep = 0;
RainRunning = true;

Text_Loading.setVisible(true);
Text_Loading.applyText(“DASHBOARD LOADING”);
Text_Loading.setCssClass(“loading-text-idle”);
Text_Remember.setVisible(false);
Text_Remember.applyText(“”);

// Initialise system status
Text_Status.setVisible(true);
Text_Status.applyText(“● SYSTEM BOOTING”);
Text_Status.setCssClass(“heartbeat-on”);

// Initialise boot sequence
BootLog = “”;
Text_BootLog.setVisible(true);
Text_BootLog.applyText(“”);
Text_BootLog.setCssClass(“boot-log”);

// Make all panels visible
Panel_1.setVisible(true);
Panel_2.setVisible(true);
Panel_3.setVisible(true);
Panel_4.setVisible(true);
Panel_5.setVisible(true);
Panel_6.setVisible(true);
Panel_7.setVisible(true);
Panel_8.setVisible(true);
Panel_9.setVisible(true);
Panel_10.setVisible(true);
Panel_11.setVisible(true);
Panel_12.setVisible(true);
Panel_13.setVisible(true);
Panel_14.setVisible(true);
Panel_15.setVisible(true);
Panel_16.setVisible(true);
Panel_17.setVisible(true);
Panel_18.setVisible(true);
Panel_19.setVisible(true);
Panel_20.setVisible(true);
Panel_21.setVisible(true);
Panel_22.setVisible(true);
Panel_23.setVisible(true);
Panel_24.setVisible(true);
Panel_25.setVisible(true);
Panel_26.setVisible(true);
Panel_27.setVisible(true);
Panel_28.setVisible(true);
Panel_29.setVisible(true);
Panel_30.setVisible(true);
Panel_31.setVisible(true);
Panel_32.setVisible(true);

// Reset all panels to dormant
Panel_1.setCssClass(“rain-dormant”);
Panel_2.setCssClass(“rain-dormant”);
Panel_3.setCssClass(“rain-dormant”);
Panel_4.setCssClass(“rain-dormant”);
Panel_5.setCssClass(“rain-dormant”);
Panel_6.setCssClass(“rain-dormant”);
Panel_7.setCssClass(“rain-dormant”);
Panel_8.setCssClass(“rain-dormant”);
Panel_9.setCssClass(“rain-dormant”);
Panel_10.setCssClass(“rain-dormant”);
Panel_11.setCssClass(“rain-dormant”);
Panel_12.setCssClass(“rain-dormant”);
Panel_13.setCssClass(“rain-dormant”);
Panel_14.setCssClass(“rain-dormant”);
Panel_15.setCssClass(“rain-dormant”);
Panel_16.setCssClass(“rain-dormant”);
Panel_17.setCssClass(“rain-dormant”);
Panel_18.setCssClass(“rain-dormant”);
Panel_19.setCssClass(“rain-dormant”);
Panel_20.setCssClass(“rain-dormant”);
Panel_21.setCssClass(“rain-dormant”);
Panel_22.setCssClass(“rain-dormant”);
Panel_23.setCssClass(“rain-dormant”);
Panel_24.setCssClass(“rain-dormant”);
Panel_25.setCssClass(“rain-dormant”);
Panel_26.setCssClass(“rain-dormant”);
Panel_27.setCssClass(“rain-dormant”);
Panel_28.setCssClass(“rain-dormant”);
Panel_29.setCssClass(“rain-dormant”);
Panel_30.setCssClass(“rain-dormant”);
Panel_31.setCssClass(“rain-dormant”);
Panel_32.setCssClass(“rain-dormant”);

// Reset progress bar
Panel_ProgressTrack.setVisible(true);
Panel_ProgressFill.setVisible(true);
Panel_ProgressTrack.setCssClass(“progress-track”);
Panel_ProgressFill.setCssClass(“progress-fill”);
Panel_ProgressFill.getLayout().setWidth(4);

// Start the animation
Timer_1.start(0.18);

8. Timer_1 — animation script

Paste the complete script below into Timer_1. Timer_1 restarts itself every 0.18 seconds until RainStep reaches 41.

// =========================================================
// 32-PANEL DIGITAL RAIN ANIMATION
// 4 rows × 8 columns
// Includes Text_Loading status display
// =========================================================


// ———————————————————
// Boot cursor state
// ———————————————————

var cursor = “”;

if ((RainStep % 4) < 2)
{
    cursor = “_”;
}

// ———————————————————
// PHASE 1 — random digital rain
// Frames 0–11
// ———————————————————

if (RainStep === 0)
{
    Text_Loading.setVisible(true);
          Text_Progress.setVisible(true);
    Text_Loading.applyText(“DASHBOARD LOADING”+ cursor);
    Text_Loading.setCssClass(“loading-text-active”);
         

    Panel_3.setCssClass(“rain-active”);
    Panel_14.setCssClass(“rain-flash”);
    Panel_27.setCssClass(“rain-active”);
}


if (RainStep === 1)
{
    Text_Loading.applyText(“DASHBOARD LOADING.”+ cursor);

    Panel_3.setCssClass(“rain-trace”);
    Panel_14.setCssClass(“rain-trace”);
    Panel_27.setCssClass(“rain-trace”);

    Panel_7.setCssClass(“rain-active”);
    Panel_18.setCssClass(“rain-process”);
    Panel_30.setCssClass(“rain-flash”);
}


if (RainStep === 2)
{
    Text_Loading.applyText(“DASHBOARD LOADING..”+ cursor);

    Panel_7.setCssClass(“rain-trace”);
    Panel_18.setCssClass(“rain-trace”);
    Panel_30.setCssClass(“rain-trace”);

    Panel_1.setCssClass(“rain-glitch”);
    Panel_11.setCssClass(“rain-active”);
    Panel_24.setCssClass(“rain-flash”);
}


if (RainStep === 3)
{
    Text_Loading.applyText(“DASHBOARD LOADING…”+ cursor);

    Panel_1.setCssClass(“rain-trace”);
    Panel_11.setCssClass(“rain-trace”);
    Panel_24.setCssClass(“rain-trace”);

    Panel_6.setCssClass(“rain-active”);
    Panel_20.setCssClass(“rain-active”);
    Panel_32.setCssClass(“rain-flash”);
}


if (RainStep === 4)
{
    Text_Loading.applyText(“INITIALISING COMPONENTS”+ cursor);

    Panel_6.setCssClass(“rain-trace”);
    Panel_20.setCssClass(“rain-trace”);
    Panel_32.setCssClass(“rain-trace”);

    Panel_9.setCssClass(“rain-flash”);
    Panel_16.setCssClass(“rain-active”);
    Panel_22.setCssClass(“rain-process”);
}


if (RainStep === 5)
{
    Text_Loading.applyText(“CONNECTING DATA SOURCES”+ cursor);
    Text_Loading.setCssClass(“loading-text-active”);

    Panel_9.setCssClass(“rain-trace”);
    Panel_16.setCssClass(“rain-trace”);
    Panel_22.setCssClass(“rain-trace”);

    Panel_4.setCssClass(“rain-active”);
    Panel_13.setCssClass(“rain-glitch”);
    Panel_29.setCssClass(“rain-flash”);
}


if (RainStep === 6)
{
    Text_Loading.applyText(“CONNECTING DATA SOURCES.”+ cursor);

    Panel_4.setCssClass(“rain-trace”);
    Panel_13.setCssClass(“rain-trace”);
    Panel_29.setCssClass(“rain-trace”);

    Panel_8.setCssClass(“rain-flash”);
    Panel_17.setCssClass(“rain-active”);
    Panel_26.setCssClass(“rain-active”);
}


if (RainStep === 7)
{
    Text_Loading.applyText(“CONNECTING DATA SOURCES..”+ cursor);

    Panel_8.setCssClass(“rain-trace”);
    Panel_17.setCssClass(“rain-trace”);
    Panel_26.setCssClass(“rain-trace”);

    Panel_2.setCssClass(“rain-active”);
    Panel_15.setCssClass(“rain-flash”);
    Panel_31.setCssClass(“rain-process”);
}


if (RainStep === 8)
{
    Text_Loading.applyText(“CONNECTING DATA SOURCES…”+ cursor);

    Panel_2.setCssClass(“rain-trace”);
    Panel_15.setCssClass(“rain-trace”);
    Panel_31.setCssClass(“rain-trace”);

    Panel_5.setCssClass(“rain-glitch”);
    Panel_19.setCssClass(“rain-active”);
    Panel_25.setCssClass(“rain-flash”);
}


if (RainStep === 9)
{
    Text_Loading.applyText(“DATA CONNECTION ESTABLISHED”+ cursor);

    Panel_5.setCssClass(“rain-trace”);
    Panel_19.setCssClass(“rain-trace”);
    Panel_25.setCssClass(“rain-trace”);

    Panel_10.setCssClass(“rain-active”);
    Panel_21.setCssClass(“rain-flash”);
    Panel_28.setCssClass(“rain-active”);
}


if (RainStep === 10)
{
    Text_Loading.applyText(“PREPARING ANALYTIC ENGINE”+ cursor);

    Panel_10.setCssClass(“rain-trace”);
    Panel_21.setCssClass(“rain-trace”);
    Panel_28.setCssClass(“rain-trace”);

    Panel_12.setCssClass(“rain-flash”);
    Panel_23.setCssClass(“rain-active”);
    Panel_30.setCssClass(“rain-glitch”);
}


if (RainStep === 11)
{
    Text_Loading.applyText(“PREPARING ANALYTIC ENGINE…”+ cursor);

    Panel_12.setCssClass(“rain-trace”);
    Panel_23.setCssClass(“rain-trace”);
    Panel_30.setCssClass(“rain-trace”);

    Panel_3.setCssClass(“rain-active”);
    Panel_18.setCssClass(“rain-flash”);
    Panel_27.setCssClass(“rain-process”);
}


// ———————————————————
// PHASE 2 — serpentine energy pulse
// Frames 12–27
// ———————————————————

if (RainStep === 12)
{
    Text_Loading.applyText(“LOADING ANALYTIC MODELS”+ cursor);
    Text_Loading.setCssClass(“loading-text-active”);

    Panel_3.setCssClass(“rain-trace”);
    Panel_18.setCssClass(“rain-trace”);
    Panel_27.setCssClass(“rain-trace”);

    Panel_1.setCssClass(“rain-flash”);
    Panel_2.setCssClass(“rain-active”);
}


if (RainStep === 13)
{
    Text_Loading.applyText(“LOADING ANALYTIC MODELS.”+ cursor);

    Panel_1.setCssClass(“rain-powered”);
    Panel_2.setCssClass(“rain-flash”);
    Panel_3.setCssClass(“rain-active”);
}


if (RainStep === 14)
{
    Text_Loading.applyText(“LOADING ANALYTIC MODELS..”+ cursor);

    Panel_2.setCssClass(“rain-powered”);
    Panel_3.setCssClass(“rain-flash”);
    Panel_4.setCssClass(“rain-active”);
}


if (RainStep === 15)
{
    Text_Loading.applyText(“LOADING ANALYTIC MODELS…”+ cursor);

    Panel_3.setCssClass(“rain-powered”);
    Panel_4.setCssClass(“rain-flash”);
    Panel_5.setCssClass(“rain-active”);
}


if (RainStep === 16)
{
    Text_Loading.applyText(“MODEL 01 INITIALISED”+ cursor);

    Panel_4.setCssClass(“rain-powered”);
    Panel_5.setCssClass(“rain-flash”);
    Panel_6.setCssClass(“rain-active”);
}


if (RainStep === 17)
{
    Text_Loading.applyText(“MODEL 02 INITIALISED”+ cursor);

    Panel_5.setCssClass(“rain-powered”);
    Panel_6.setCssClass(“rain-flash”);
    Panel_7.setCssClass(“rain-active”);
}


if (RainStep === 18)
{
    Text_Loading.applyText(“MODEL 03 INITIALISED”+ cursor);

    Panel_6.setCssClass(“rain-powered”);
    Panel_7.setCssClass(“rain-flash”);
    Panel_8.setCssClass(“rain-active”);
}


if (RainStep === 19)
{
    Text_Loading.applyText(“ACTIVATING CALCULATION LAYER”+ cursor);

    Panel_7.setCssClass(“rain-powered”);
    Panel_8.setCssClass(“rain-flash”);
    Panel_16.setCssClass(“rain-active”);
}


if (RainStep === 20)
{
    Text_Loading.applyText(“ACTIVATING CALCULATION LAYER.”+ cursor);

    Panel_8.setCssClass(“rain-powered”);
    Panel_16.setCssClass(“rain-flash”);
    Panel_15.setCssClass(“rain-active”);
}


if (RainStep === 21)
{
    Text_Loading.applyText(“ACTIVATING CALCULATION LAYER..”+ cursor);

    Panel_16.setCssClass(“rain-powered”);
    Panel_15.setCssClass(“rain-flash”);
    Panel_14.setCssClass(“rain-active”);
}


if (RainStep === 22)
{
    Text_Loading.applyText(“ACTIVATING CALCULATION LAYER…”+ cursor);

    Panel_15.setCssClass(“rain-powered”);
    Panel_14.setCssClass(“rain-flash”);
    Panel_13.setCssClass(“rain-active”);
}


if (RainStep === 23)
{
    Text_Loading.applyText(“CALCULATIONS ONLINE”+ cursor);

    Panel_14.setCssClass(“rain-powered”);
    Panel_13.setCssClass(“rain-flash”);
    Panel_12.setCssClass(“rain-active”);
}


if (RainStep === 24)
{
    Text_Loading.applyText(“APPLYING BUSINESS LOGIC”+ cursor);

    Panel_13.setCssClass(“rain-powered”);
    Panel_12.setCssClass(“rain-flash”);
    Panel_11.setCssClass(“rain-active”);
}


if (RainStep === 25)
{
    Text_Loading.applyText(“APPLYING BUSINESS LOGIC.”+ cursor);

    Panel_12.setCssClass(“rain-powered”);
    Panel_11.setCssClass(“rain-flash”);
    Panel_10.setCssClass(“rain-active”);
}


if (RainStep === 26)
{
    Text_Loading.applyText(“APPLYING BUSINESS LOGIC..”+ cursor);

    Panel_11.setCssClass(“rain-powered”);
    Panel_10.setCssClass(“rain-flash”);
    Panel_9.setCssClass(“rain-active”);
}


if (RainStep === 27)
{
    Text_Loading.applyText(“BUSINESS LOGIC VALIDATED”+ cursor);

    Panel_10.setCssClass(“rain-powered”);
    Panel_9.setCssClass(“rain-flash”);

    Panel_17.setCssClass(“rain-active”);
    Panel_18.setCssClass(“rain-active”);
    Panel_19.setCssClass(“rain-active”);
    Panel_20.setCssClass(“rain-active”);
    Panel_21.setCssClass(“rain-active”);
    Panel_22.setCssClass(“rain-active”);
    Panel_23.setCssClass(“rain-active”);
    Panel_24.setCssClass(“rain-active”);
}


// ———————————————————
// PHASE 3 — row ignition
// Frames 28–31
// ———————————————————

if (RainStep === 28)
{
    Text_Loading.applyText(“VALIDATING DASHBOARD COMPONENTS”+ cursor);
    Text_Loading.setCssClass(“loading-text-active”);

    Panel_9.setCssClass(“rain-powered”);

    Panel_17.setCssClass(“rain-flash”);
    Panel_18.setCssClass(“rain-flash”);
    Panel_19.setCssClass(“rain-flash”);
    Panel_20.setCssClass(“rain-flash”);
    Panel_21.setCssClass(“rain-flash”);
    Panel_22.setCssClass(“rain-flash”);
    Panel_23.setCssClass(“rain-flash”);
    Panel_24.setCssClass(“rain-flash”);
}


if (RainStep === 29)
{
    Text_Loading.applyText(“VALIDATING DASHBOARD COMPONENTS.”+ cursor);

    Panel_17.setCssClass(“rain-powered”);
    Panel_18.setCssClass(“rain-powered”);
    Panel_19.setCssClass(“rain-powered”);
    Panel_20.setCssClass(“rain-powered”);
    Panel_21.setCssClass(“rain-powered”);
    Panel_22.setCssClass(“rain-powered”);
    Panel_23.setCssClass(“rain-powered”);
    Panel_24.setCssClass(“rain-powered”);

    Panel_25.setCssClass(“rain-active”);
    Panel_26.setCssClass(“rain-active”);
    Panel_27.setCssClass(“rain-active”);
    Panel_28.setCssClass(“rain-active”);
    Panel_29.setCssClass(“rain-active”);
    Panel_30.setCssClass(“rain-active”);
    Panel_31.setCssClass(“rain-active”);
    Panel_32.setCssClass(“rain-active”);
}


if (RainStep === 30)
{
    Text_Loading.applyText(“VALIDATING DASHBOARD COMPONENTS..”+ cursor);

    Panel_25.setCssClass(“rain-flash”);
    Panel_26.setCssClass(“rain-flash”);
    Panel_27.setCssClass(“rain-flash”);
    Panel_28.setCssClass(“rain-flash”);
    Panel_29.setCssClass(“rain-flash”);
    Panel_30.setCssClass(“rain-flash”);
    Panel_31.setCssClass(“rain-flash”);
    Panel_32.setCssClass(“rain-flash”);
}


if (RainStep === 31)
{
    Text_Loading.applyText(“COMPONENT VALIDATION COMPLETE”+ cursor);

    Panel_25.setCssClass(“rain-powered”);
    Panel_26.setCssClass(“rain-powered”);
    Panel_27.setCssClass(“rain-powered”);
    Panel_28.setCssClass(“rain-powered”);
    Panel_29.setCssClass(“rain-powered”);
    Panel_30.setCssClass(“rain-powered”);
    Panel_31.setCssClass(“rain-powered”);
    Panel_32.setCssClass(“rain-powered”);
}


// ———————————————————
// PHASE 4 — vertical scanner sweep
// Frames 32–39
// ———————————————————

if (RainStep === 32)
{
    Text_Loading.applyText(“ACTIVATING VISUAL LAYER”+ cursor);
    Text_Loading.setCssClass(“loading-text-active”);

    Panel_1.setCssClass(“rain-flash”);
    Panel_9.setCssClass(“rain-flash”);
    Panel_17.setCssClass(“rain-flash”);
    Panel_25.setCssClass(“rain-flash”);
}


if (RainStep === 33)
{
    Text_Loading.applyText(“ACTIVATING VISUAL LAYER.”+ cursor);

    Panel_1.setCssClass(“rain-powered”);
    Panel_9.setCssClass(“rain-powered”);
    Panel_17.setCssClass(“rain-powered”);
    Panel_25.setCssClass(“rain-powered”);

    Panel_2.setCssClass(“rain-flash”);
    Panel_10.setCssClass(“rain-flash”);
    Panel_18.setCssClass(“rain-flash”);
    Panel_26.setCssClass(“rain-flash”);
}


if (RainStep === 34)
{
    Text_Loading.applyText(“ACTIVATING VISUAL LAYER..”+ cursor);

    Panel_2.setCssClass(“rain-powered”);
    Panel_10.setCssClass(“rain-powered”);
    Panel_18.setCssClass(“rain-powered”);
    Panel_26.setCssClass(“rain-powered”);

    Panel_3.setCssClass(“rain-flash”);
    Panel_11.setCssClass(“rain-flash”);
    Panel_19.setCssClass(“rain-flash”);
    Panel_27.setCssClass(“rain-flash”);
}


if (RainStep === 35)
{
    Text_Loading.applyText(“ACTIVATING VISUAL LAYER…”+ cursor);

    Panel_3.setCssClass(“rain-powered”);
    Panel_11.setCssClass(“rain-powered”);
    Panel_19.setCssClass(“rain-powered”);
    Panel_27.setCssClass(“rain-powered”);

    Panel_4.setCssClass(“rain-flash”);
    Panel_12.setCssClass(“rain-flash”);
    Panel_20.setCssClass(“rain-flash”);
    Panel_28.setCssClass(“rain-flash”);
}


if (RainStep === 36)
{
    Text_Loading.applyText(“RENDERING DASHBOARD”+ cursor);

    Panel_4.setCssClass(“rain-powered”);
    Panel_12.setCssClass(“rain-powered”);
    Panel_20.setCssClass(“rain-powered”);
    Panel_28.setCssClass(“rain-powered”);

    Panel_5.setCssClass(“rain-flash”);
    Panel_13.setCssClass(“rain-flash”);
    Panel_21.setCssClass(“rain-flash”);
    Panel_29.setCssClass(“rain-flash”);
}


if (RainStep === 37)
{
    Text_Loading.applyText(“RENDERING DASHBOARD.”+ cursor);

    Panel_5.setCssClass(“rain-powered”);
    Panel_13.setCssClass(“rain-powered”);
    Panel_21.setCssClass(“rain-powered”);
    Panel_29.setCssClass(“rain-powered”);

    Panel_6.setCssClass(“rain-flash”);
    Panel_14.setCssClass(“rain-flash”);
    Panel_22.setCssClass(“rain-flash”);
    Panel_30.setCssClass(“rain-flash”);
}


if (RainStep === 38)
{
    Text_Loading.applyText(“RENDERING DASHBOARD..”+ cursor);

    Panel_6.setCssClass(“rain-powered”);
    Panel_14.setCssClass(“rain-powered”);
    Panel_22.setCssClass(“rain-powered”);
    Panel_30.setCssClass(“rain-powered”);

    Panel_7.setCssClass(“rain-flash”);
    Panel_15.setCssClass(“rain-flash”);
    Panel_23.setCssClass(“rain-flash”);
    Panel_31.setCssClass(“rain-flash”);
}


if (RainStep === 39)
{
    Text_Loading.applyText(“RENDERING DASHBOARD…”+ cursor);

    Panel_7.setCssClass(“rain-powered”);
    Panel_15.setCssClass(“rain-powered”);
    Panel_23.setCssClass(“rain-powered”);
    Panel_31.setCssClass(“rain-powered”);

    Panel_8.setCssClass(“rain-flash”);
    Panel_16.setCssClass(“rain-flash”);
    Panel_24.setCssClass(“rain-flash”);
    Panel_32.setCssClass(“rain-flash”);
}


// ———————————————————
// PHASE 5 — full system flash
// Frame 40
// ———————————————————

if (RainStep === 40)
{
    Text_Loading.applyText(“FINALISING” + cursor);
    Text_Loading.setCssClass(“loading-text-flash”);

    Panel_1.setCssClass(“rain-flash”);
    Panel_2.setCssClass(“rain-flash”);
    Panel_3.setCssClass(“rain-flash”);
    Panel_4.setCssClass(“rain-flash”);
    Panel_5.setCssClass(“rain-flash”);
    Panel_6.setCssClass(“rain-flash”);
    Panel_7.setCssClass(“rain-flash”);
    Panel_8.setCssClass(“rain-flash”);

    Panel_9.setCssClass(“rain-flash”);
    Panel_10.setCssClass(“rain-flash”);
    Panel_11.setCssClass(“rain-flash”);
    Panel_12.setCssClass(“rain-flash”);
    Panel_13.setCssClass(“rain-flash”);
    Panel_14.setCssClass(“rain-flash”);
    Panel_15.setCssClass(“rain-flash”);
    Panel_16.setCssClass(“rain-flash”);

    Panel_17.setCssClass(“rain-flash”);
    Panel_18.setCssClass(“rain-flash”);
    Panel_19.setCssClass(“rain-flash”);
    Panel_20.setCssClass(“rain-flash”);
    Panel_21.setCssClass(“rain-flash”);
    Panel_22.setCssClass(“rain-flash”);
    Panel_23.setCssClass(“rain-flash”);
    Panel_24.setCssClass(“rain-flash”);

    Panel_25.setCssClass(“rain-flash”);
    Panel_26.setCssClass(“rain-flash”);
    Panel_27.setCssClass(“rain-flash”);
    Panel_28.setCssClass(“rain-flash”);
    Panel_29.setCssClass(“rain-flash”);
    Panel_30.setCssClass(“rain-flash”);
    Panel_31.setCssClass(“rain-flash”);
    Panel_32.setCssClass(“rain-flash”);
}


// ———————————————————
// PHASE 6 — final state
// Frame 41
// ———————————————————

if (RainStep === 41)
{
    Text_Loading.applyText(“DASHBOARD READY”);
    Text_Loading.setCssClass(“loading-text-ready”);

    Panel_1.setCssClass(“rain-final”);
    Panel_2.setCssClass(“rain-final”);
    Panel_3.setCssClass(“rain-final”);
    Panel_4.setCssClass(“rain-final”);
    Panel_5.setCssClass(“rain-final”);
    Panel_6.setCssClass(“rain-final”);
    Panel_7.setCssClass(“rain-final”);
    Panel_8.setCssClass(“rain-final”);

    Panel_9.setCssClass(“rain-final”);
    Panel_10.setCssClass(“rain-final”);
    Panel_11.setCssClass(“rain-final”);
    Panel_12.setCssClass(“rain-final”);
    Panel_13.setCssClass(“rain-final”);
    Panel_14.setCssClass(“rain-final”);
    Panel_15.setCssClass(“rain-final”);
    Panel_16.setCssClass(“rain-final”);

    Panel_17.setCssClass(“rain-final”);
    Panel_18.setCssClass(“rain-final”);
    Panel_19.setCssClass(“rain-final”);
    Panel_20.setCssClass(“rain-final”);
    Panel_21.setCssClass(“rain-final”);
    Panel_22.setCssClass(“rain-final”);
    Panel_23.setCssClass(“rain-final”);
    Panel_24.setCssClass(“rain-final”);

    Panel_25.setCssClass(“rain-final”);
    Panel_26.setCssClass(“rain-final”);
    Panel_27.setCssClass(“rain-final”);
    Panel_28.setCssClass(“rain-final”);
    Panel_29.setCssClass(“rain-final”);
    Panel_30.setCssClass(“rain-final”);
    Panel_31.setCssClass(“rain-final”);
    Panel_32.setCssClass(“rain-final”);
         
          // Show final message
Text_Remember.setVisible(true);
Text_Remember.applyText(“Remember…\n\nSORT YOUR DATA FIRST.”);
Text_Remember.setCssClass(“remember-message”);

    Timer_1.stop();

    RainRunning = false;

 
}

// ———————————————————
// Progress bar
// 440px track with a small internal margin
// ———————————————————

var progressWidth = 4;

if (RainStep === 0)
{
    progressWidth = 4;
}

if (RainStep === 1)
{
    progressWidth = 14;
}

if (RainStep === 2)
{
    progressWidth = 25;
}

if (RainStep === 3)
{
    progressWidth = 35;
}

if (RainStep === 4)
{
    progressWidth = 46;
}

if (RainStep === 5)
{
    progressWidth = 56;
}

if (RainStep === 6)
{
    progressWidth = 67;
}

if (RainStep === 7)
{
    progressWidth = 77;
}

if (RainStep === 8)
{
    progressWidth = 88;
}

if (RainStep === 9)
{
    progressWidth = 98;
}

if (RainStep === 10)
{
    progressWidth = 109;
}

if (RainStep === 11)
{
    progressWidth = 119;
}

if (RainStep === 12)
{
    progressWidth = 130;
}

if (RainStep === 13)
{
    progressWidth = 140;
}

if (RainStep === 14)
{
    progressWidth = 151;
}

if (RainStep === 15)
{
    progressWidth = 161;
}

if (RainStep === 16)
{
    progressWidth = 172;
}

if (RainStep === 17)
{
    progressWidth = 182;
}

if (RainStep === 18)
{
    progressWidth = 193;
}

if (RainStep === 19)
{
    progressWidth = 203;
}

if (RainStep === 20)
{
    progressWidth = 214;
}

if (RainStep === 21)
{
    progressWidth = 224;
}

if (RainStep === 22)
{
    progressWidth = 235;
}

if (RainStep === 23)
{
    progressWidth = 245;
}

if (RainStep === 24)
{
    progressWidth = 256;
}

if (RainStep === 25)
{
    progressWidth = 266;
}

if (RainStep === 26)
{
    progressWidth = 277;
}

if (RainStep === 27)
{
    progressWidth = 287;
}

if (RainStep === 28)
{
    progressWidth = 298;
}

if (RainStep === 29)
{
    progressWidth = 308;
}

if (RainStep === 30)
{
    progressWidth = 319;
}

if (RainStep === 31)
{
    progressWidth = 329;
}

if (RainStep === 32)
{
    progressWidth = 340;
}

if (RainStep === 33)
{
    progressWidth = 350;
}

if (RainStep === 34)
{
    progressWidth = 361;
}

if (RainStep === 35)
{
    progressWidth = 371;
}

if (RainStep === 36)
{
    progressWidth = 382;
}

if (RainStep === 37)
{
    progressWidth = 392;
}

if (RainStep === 38)
{
    progressWidth = 403;
}

if (RainStep === 39)
{
    progressWidth = 413;
}

if (RainStep === 40)
{
    progressWidth = 424;
    Panel_ProgressFill.setCssClass(“progress-fill-flash”);
}

if (RainStep === 41)
{
    progressWidth = 436;
    Panel_ProgressFill.setCssClass(“progress-fill-ready”);
}

Panel_ProgressFill.getLayout().setWidth(progressWidth);










// ———————————————————
// Tongue-in-cheek boot sequence
// Safe version: tied directly to existing RainStep frames
// ———————————————————

if (RainStep === 0)
{
    BootLog = “> Initialising analytics kernel……… OK”;
    Text_BootLog.applyText(BootLog);
}

if (RainStep === 2)
{
    BootLog = BootLog + “\n> Loading semantic layer…………… OK”;
    Text_BootLog.applyText(BootLog);
}

if (RainStep === 4)
{
    BootLog = BootLog + “\n> Unified semantic layer…………… We remember Universes.”;
    Text_BootLog.applyText(BootLog);
}

if (RainStep === 6)
{
    BootLog = BootLog + “\n> Connecting BW Live………………. OK”;
    Text_BootLog.applyText(BootLog);
}

if (RainStep === 8)
{
    BootLog = BootLog + “\n> Loading CDS Views……………….. OK”;
    Text_BootLog.applyText(BootLog);
}

if (RainStep === 10)
{
    BootLog = BootLog + “\n> Loading Data Products……………. Still defining them.”;
    Text_BootLog.applyText(BootLog);
}

if (RainStep === 12)
{
    BootLog = BootLog + “\n> Validating KPI definitions……….. Debate continues.”;
    Text_BootLog.applyText(BootLog);
}

if (RainStep === 14)
{
    BootLog = BootLog + “\n> Loading tabular reporting………… BOBJ sends its regards.”;
    Text_BootLog.applyText(BootLog);
}

if (RainStep === 16)
{
    BootLog = BootLog + “\n> Building single source of truth…… Version 14.”;
    Text_BootLog.applyText(BootLog);
}

if (RainStep === 18)
{
    BootLog = BootLog + “\n> Initialising AI assistant………… Buzzwords detected.”;
    Text_BootLog.applyText(BootLog);
}

if (RainStep === 20)
{
    BootLog = BootLog + “\n> Measuring AI hype……………….. 97%”;
    Text_BootLog.applyText(BootLog);
}

if (RainStep === 22)
{
    BootLog = BootLog + “\n> Measuring production value……….. Still loading.”;
    Text_BootLog.applyText(BootLog);
}

if (RainStep === 24)
{
    BootLog = BootLog + “\n> Generating executive summary……… \”AI-first\” inserted.”;
    Text_BootLog.applyText(BootLog);
}

if (RainStep === 26)
{
    BootLog = BootLog + “\n> Validating AI predictions………… Human judgement retained.”;
    Text_BootLog.applyText(BootLog);
}

if (RainStep === 28)
{
    BootLog = BootLog + “\n> Trusting AI completely…………… Negative.”;
    Text_BootLog.applyText(BootLog);
}

if (RainStep === 30)
{
    BootLog = BootLog + “\n> Loading AI assistant…………….. Trust starts with clean data.”;
    Text_BootLog.applyText(BootLog);
}

if (RainStep === 32)
{
    BootLog = BootLog + “\n> Preparing executive dashboard…….. More green requested.”;
    Text_BootLog.applyText(BootLog);
}

if (RainStep === 34)
{
    BootLog = BootLog + “\n> Enabling self-service……………. Excel standing by.”;
    Text_BootLog.applyText(BootLog);
}

if (RainStep === 36)
{
    BootLog = BootLog + “\n> Initialising dashboard scripts……. console.log() enabled.”;
    Text_BootLog.applyText(BootLog);
}

if (RainStep === 37)
{
    BootLog = BootLog + “\n> Detecting spreadsheet exports…….. Inevitable.”;
    Text_BootLog.applyText(BootLog);
}

if (RainStep === 38)
{
    BootLog = BootLog + “\n> Refreshing cache…………………. CTRL+F5 not required.”;
    Text_BootLog.applyText(BootLog);
}

if (RainStep === 40)
{
    BootLog = BootLog + “\n> Finalising dashboard…………….. COMPLETE”;
    Text_BootLog.applyText(BootLog);
}

if (RainStep === 41)
{
    Text_BootLog.setCssClass(“boot-log-ready”);
}











// ———————————————————
// Slow heartbeat status indicator
// Bright for 6 frames, dim for 6 frames
// ———————————————————

// ———————————————————
// Status LED
// ———————————————————

if (RainStep < 41)
{
    if ((RainStep % 8) < 2)
    {
        Text_Status.applyText(“● SYSTEM BOOTING”);
        Text_Status.setCssClass(“heartbeat-on”);
    }
    else
    {
        Text_Status.applyText(“○ SYSTEM BOOTING”);
        Text_Status.setCssClass(“heartbeat-off”);
    }
}
else
{
    Text_Status.applyText(“● SYSTEM ONLINE”);
    Text_Status.setCssClass(“heartbeat-on”);
}












// ———————————————————
// Continue animation
// ———————————————————

if (RainStep < 41)
{
    RainStep = RainStep + 1;
          var percent = ConvertUtils.numberToString(Math.round((RainStep / 41) * 100));  
    Text_Progress.applyText(percent + “%”);

    Timer_1.start(0.18);
}

9. Expected result

FramesStageWhat you should see
0–11Digital rainRandom cells activate, flash, glitch and leave traces.
12–27Energy pulseThe animation moves through the grid in a controlled sequence.
28–31Row ignitionWhole rows transition into powered states.
32–39Scanner sweepColumns flash across the grid.
40Final flashAll 32 panels flash together.
41ReadyPanels become final cards; DASHBOARD READY and SYSTEM ONLINE appear.

10. Quick checks if it does not work

ProblemCheck
Nothing happensPage_1 onInitialization contains Timer_2.start(1);
Panels stay plainCSS is present and the panel IDs exactly match Panel_1 to Panel_32.
Timer errorTimer_1 and Timer_2 exist and scripts are pasted into the correct timer events.
Progress does not movePanel_ProgressFill exists and its width can be controlled by getLayout().setWidth().
Percentage errorsText_Progress exists with the exact ID.
Boot log stays emptyBootLog is a string variable and Text_BootLog exists.
Final state never appearsRainStep is an integer, starts at 0, and Timer_1 is allowed to reach frame 41.

11. CSS class reference

Main classes used by the scripts:

  • Panels: rain-dormant, rain-trace, rain-active, rain-process, rain-glitch, rain-flash, rain-powered, rain-final.
  • Loading text: loading-text-idle, loading-text-active, loading-text-flash, loading-text-ready.
  • Progress: progress-track, progress-fill, progress-fill-flash, progress-fill-ready.
  • Status/log: heartbeat-on, heartbeat-off, boot-log, boot-log-ready, remember-message.
  • The supplied CSS also contains rain-core-idle, rain-core-active and rain-core-flash for a shape-based central core. The current Timer_1 script does not reference these classes.

12. Build checklist

  • 32 panels created and named correctly.
  • Five text widgets created and named correctly.
  • Progress track and fill created.
  • BootLog, RainRunning and RainStep variables created.
  • Timer_1 and Timer_2 created.
  • CSS pasted.
  • Timer_2.start(1); added to Page_1 onInitialization.
  • Timer_2 script pasted.
  • Timer_1 script pasted.
  • Run the application and confirm the loader reaches DASHBOARD READY.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top