# Animated Number

Animated numeric transitions for process values and counters.

## Installation

Download: /api/catalog/animated-number/download

Ignition Perspective 8.3. In a development project, choose Designer > File > Import and select the ZIP. Preserve the view and style-class paths. Review resource conflicts before replacing anything.

Append stylesheet-snippet.css to Perspective Styles > stylesheet.css (enable Advanced Stylesheet). Preserve existing CSS. This supporting file is not imported automatically.

Add an Embedded View (ia.display.view), set props.path to Viewcraft/Components/UI/AnimatedNumber/AnimatedNumber, and configure props.params using the contract below. Connect your own data in the host view. The package does not include live tags, page configuration or Gateway settings.

## Parameters

Types are inferred from saved defaults; directions come from native propConfig. These are not full schemas or validated ranges.

| Parameter | Type | Direction | Default |

| --- | --- | --- | --- |

| value | number | input | 72.4 |

| decimals | number | input | 1 |

| unit | string | input | "°C" |

| prefix | string | input | "" |

| size | string | input | "md" |

| format | string | input | "" |

| alarm | boolean | input | false |

| reducedMotion | boolean | input | false |

| mono | boolean | input | true |

## Embedded View usage

```json

{
  "type": "ia.display.view",
  "props": {
    "path": "Viewcraft/Components/UI/AnimatedNumber/AnimatedNumber",
    "params": {
      "value": 72.4,
      "decimals": 1,
      "unit": "°C",
      "prefix": "",
      "size": "md",
      "format": "",
      "alarm": false,
      "reducedMotion": false,
      "mono": true
    },
    "useDefaultViewWidth": false,
    "useDefaultViewHeight": false
  }
}

```

## Verification

Source and archive hashes are checked. Designer import acceptance has not been completed for this archive; test in your development project before production.

## Files

### com.inductiveautomation.perspective/views/Viewcraft/Components/UI/AnimatedNumber/AnimatedNumber/view.json

```json

{
  "custom": {
    "pulse": false,
    "prev": 72.4
  },
  "params": {
    "value": 72.4,
    "decimals": 1,
    "unit": "°C",
    "prefix": "",
    "size": "md",
    "format": "",
    "alarm": false,
    "reducedMotion": false,
    "mono": true
  },
  "propConfig": {
    "params.value": {
      "paramDirection": "input",
      "persistent": true,
      "onChange": {
        "type": "script",
        "enabled": true,
        "script": "\ttry:\n\t\tv = float(currentValue.value)\n\texcept:\n\t\tv = 0.0\n\ttry:\n\t\tprev = float(self.view.custom.prev)\n\texcept:\n\t\tprev = v\n\tself.view.custom.prev = v\n\tif coalesce(self.view.params.reducedMotion, False):\n\t\tself.view.custom.pulse = False\n\t\treturn\n\t# retrigger CSS animation\n\tself.view.custom.pulse = False\n\tself.view.custom.pulse = True\n"
      }
    },
    "params.decimals": {
      "paramDirection": "input",
      "persistent": true
    },
    "params.unit": {
      "paramDirection": "input",
      "persistent": true
    },
    "params.prefix": {
      "paramDirection": "input",
      "persistent": true
    },
    "params.size": {
      "paramDirection": "input",
      "persistent": true
    },
    "params.format": {
      "paramDirection": "input",
      "persistent": true
    },
    "params.alarm": {
      "paramDirection": "input",
      "persistent": true
    },
    "params.reducedMotion": {
      "paramDirection": "input",
      "persistent": true
    },
    "params.mono": {
      "paramDirection": "input",
      "persistent": true
    }
  },
  "props": {
    "defaultSize": {
      "width": 220,
      "height": 56
    }
  },
  "root": {
    "type": "ia.container.flex",
    "version": 0,
    "meta": {
      "name": "KpiShell"
    },
    "props": {
      "direction": "row",
      "alignItems": "baseline",
      "style": {
        "classes": "vc/kpi-number-shell",
        "gap": "0px"
      }
    },
    "children": [
      {
        "type": "ia.display.label",
        "version": 0,
        "meta": {
          "name": "Prefix"
        },
        "position": {
          "grow": 0,
          "shrink": 0,
          "basis": "auto"
        },
        "props": {
          "text": "",
          "style": {
            "classes": "vc/kpi-number vc/kpi-number-md",
            "color": "#a1a1aa"
          }
        },
        "propConfig": {
          "props.text": {
            "binding": {
              "type": "property",
              "config": {
                "path": "view.params.prefix"
              }
            }
          },
          "meta.visible": {
            "binding": {
              "type": "expr",
              "config": {
                "expression": "len(coalesce({view.params.prefix}, '')) > 0"
              }
            }
          }
        }
      },
      {
        "type": "ia.display.label",
        "version": 0,
        "meta": {
          "name": "Value"
        },
        "position": {
          "grow": 0,
          "shrink": 0,
          "basis": "auto"
        },
        "props": {
          "text": "72.4",
          "style": {
            "classes": "vc/kpi-number vc/kpi-number-md vc/kpi-number-mono"
          }
        },
        "propConfig": {
          "props.text": {
            "binding": {
              "type": "expr",
              "config": {
                "expression": "if(len(coalesce({view.params.format}, '')) > 0, numberFormat({view.params.value}, {view.params.format}), if(coalesce({view.params.decimals}, 0) = 0, numberFormat({view.params.value}, '#,##0'), if(coalesce({view.params.decimals}, 0) = 1, numberFormat({view.params.value}, '#,##0.0'), numberFormat({view.params.value}, '#,##0.00'))))"
              }
            }
          },
          "props.style.classes": {
            "binding": {
              "type": "expr",
              "config": {
                "expression": "concat(\"vc/kpi-number vc/kpi-number-mono \", if({view.params.size} = \"sm\", \"vc/kpi-number-sm\", if({view.params.size} = \"lg\", \"vc/kpi-number-lg\", \"vc/kpi-number-md\")), if(coalesce({view.params.alarm}, false), \" vc/kpi-number-alarm\", \"\"), if(coalesce({view.params.reducedMotion}, false), \"\", if(coalesce({view.custom.pulse}, false), \" vc/kpi-number-pulse\", \"\")))"
              }
            }
          }
        }
      },
      {
        "type": "ia.display.label",
        "version": 0,
        "meta": {
          "name": "Unit"
        },
        "position": {
          "grow": 0,
          "shrink": 0,
          "basis": "auto"
        },
        "props": {
          "text": "°C",
          "style": {
            "classes": "vc/kpi-number-unit"
          }
        },
        "propConfig": {
          "props.text": {
            "binding": {
              "type": "property",
              "config": {
                "path": "view.params.unit"
              }
            }
          },
          "meta.visible": {
            "binding": {
              "type": "expr",
              "config": {
                "expression": "len(coalesce({view.params.unit}, '')) > 0"
              }
            }
          }
        }
      }
    ]
  }
}


```

### com.inductiveautomation.perspective/views/Viewcraft/Components/UI/AnimatedNumber/AnimatedNumber/resource.json

```json

{
  "scope": "G",
  "version": 1,
  "restricted": false,
  "overridable": true,
  "files": [
    "view.json"
  ]
}

```

### stylesheet-snippet.css

```css


[class~="psc-vc/kpi-number"], .psc-vc\/kpi-number {
  font-variant-numeric: tabular-nums !important;
  font-feature-settings: "tnum" 1 !important;
  color: var(--vc-foreground, #fafafa) !important;
  font-weight: 600 !important;
  line-height: 1 !important;
  letter-spacing: -0.02em !important;
  white-space: nowrap !important;
}
[class~="psc-vc/kpi-number-sm"], .psc-vc\/kpi-number-sm { font-size: 24px !important; }
[class~="psc-vc/kpi-number-md"], .psc-vc\/kpi-number-md { font-size: 32px !important; }
[class~="psc-vc/kpi-number-lg"], .psc-vc\/kpi-number-lg { font-size: 48px !important; }
[class~="psc-vc/kpi-number-mono"], .psc-vc\/kpi-number-mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace !important;
}
[class~="psc-vc/kpi-number-alarm"], .psc-vc\/kpi-number-alarm { color: hsl(38 92% 50%) !important; }
[class~="psc-vc/kpi-number-unit"], .psc-vc\/kpi-number-unit {
  color: var(--vc-muted-fg, #a1a1aa) !important;
  font-weight: 500 !important;
  font-size: 0.45em !important;
  margin-left: 0.25em !important;
  letter-spacing: 0 !important;
}
[class~="psc-vc/kpi-number-shell"], .psc-vc\/kpi-number-shell {
  display: flex !important;
  flex-direction: row !important;
  align-items: baseline !important;
  gap: 0 !important;
  min-width: 0 !important;
}
[class~="psc-vc/kpi-number-pulse"], .psc-vc\/kpi-number-pulse {
  animation: vc-kpi-swap 160ms ease-out !important;
}
@media (prefers-reduced-motion: reduce) {
  [class~="psc-vc/kpi-number-pulse"], .psc-vc\/kpi-number-pulse { animation: none !important; }
}
[class~="psc-vc/lab-hmi-page"] [class~="psc-vc/kpi-number"], .psc-vc\/lab-hmi-page .psc-vc\/kpi-number{
  font-variant-numeric:tabular-nums!important;
  letter-spacing:-0.02em!important;
  font-weight:600!important;
}
@media (prefers-reduced-motion:reduce){
  [class~="psc-vc/lab-hmi-page"] [class~="psc-vc/kpi-number-pulse"], .psc-vc\/lab-hmi-page .psc-vc\/kpi-number-pulse{
    transition:none!important;
  }
}
[class~="psc-vc/lab-hmi-page"] [class~="psc-vc/kpi-number"], .psc-vc\/lab-hmi-page .psc-vc\/kpi-number{
  font-variant-numeric:tabular-nums!important;
  letter-spacing:-0.02em!important;
}
@keyframes vc-kpi-swap {
  0% { opacity: 0.35; transform: translateY(18%); }
  100% { opacity: 1; transform: translateY(0); }
}

```