# EZPPLauncher Theme API 2.0 API 2.0 is a declarative theme format. Instead of shipping a JavaScript bundle that mounts its own UI, a theme describes its background, effects, audio, fonts and freeform layers in `theme.json`. The launcher renders it, and the built-in advanced editor can create and edit these themes without writing code. Themes can opt into a custom **Svelte layer** when they need behavior that data alone cannot express; that layer runs theme-authored JavaScript and therefore needs an explicit trust prompt. API 1.0 themes continue to work unchanged. Pick the API that fits the theme: | | API 1.0 | API 2.0 | | ----------------------- | ------------------------------------------------- | ---------------------------------------------- | | Rendering | Svelte bundle (`entry`) | Launcher-rendered | | Files | `theme.json`, `bundle.js`, `style.css`, `assets/` | `theme.json`, `assets/` | | Created with | `create-ezpplauncher-theme` | Launcher editor or `create-ezpplauncher-theme` | | Scripts / arbitrary DOM | Yes | Optional custom Svelte layer (trust prompt) | | Cross-platform | Depends on the bundle | Yes | --- ## Package layout A packaged `.ezpplauncher-theme` file is a zip with this structure: ``` theme.json assets/ background.webm layer.png music.mp3 font.woff2 preview.png # optional thumbnail ``` An installed theme lives in: ``` # Windows C:\Users\\.ezpplauncher\themes\\ # macOS / Linux ~/.ezpplauncher/themes// ``` --- ## `theme.json` ```json { "name": "Midnight", "version": "1.0.0", "apiVersion": "2.0", "author": "Your Name", "description": "A dark gradient with drifting stars.", "preview": "preview.png", "background": { "type": "gradient", "from": "#181825", "to": "#3b1d4f", "angle": 135, "opacity": 1 }, "overlay": { "color": "#000000", "opacity": 0.2, "vignette": 0.35 }, "effects": { "type": "stars", "density": 40, "speed": 1, "color": "#ffd6f2" }, "typography": { "body": "Sora Variable", "heading": "Bebas Neue", "mono": "JetBrains Mono Variable" }, "fonts": [ { "family": "My Display Font", "src": "display.woff2", "weight": "400", "style": "normal" } ], "groups": [ { "id": "branding", "name": "Branding", "opacity": 1 } ], "elements": [ { "id": "tagline", "groupId": "branding", "type": "text", "text": "MIDNIGHT", "x": 640, "y": 84, "width": 300, "height": 72, "fontFamily": "Bebas Neue", "fontSize": 46, "fontWeight": 400, "color": "#ffffff", "align": "right", "verticalAlign": "center", "letterSpacing": 2 } ], "audio": { "src": "music.mp3", "loop": true }, "variables": { "player": "Guest", "clicks": 0 }, "accentColor": "#ff006e", "iconSet": "lucide", "css": "" } ``` ### Metadata | Field | Type | Required | Notes | | ------------- | ------ | -------- | ---------------------------------------------------------------- | | `name` | string | yes | Display name; also used for the install folder | | `version` | string | yes | Semver, used for update checks | | `apiVersion` | string | yes | Must start with `2` (use `"2.0"`) | | `author` | string | yes | Shown in the theme manager | | `description` | string | no | Shown on the theme card | | `nsfw` | bool | no | Marks the theme as adult content (`18+` badge) | | `preview` | string | no | Card thumbnail; the editor generates `preview.png` | | `accentColor` | string | no | Hex color used for focus rings and active UI states | | `iconSet` | string | no | Launcher icon family: `lucide`, `phosphor` or `tabler` | | `css` | string | no | Extra CSS injected while the theme is active | | `behaviors` | array | no | Declarative WHEN / IF / THEN rules; see **Theme logic** | | `variables` | object | no | Starting values for placeholders and rules; see **Dynamic text** | ### Background `background.type` selects the layer: ```json { "type": "color", "color": "#181825", "opacity": 1 } ``` ```json { "type": "gradient", "from": "#181825", "to": "#3b1d4f", "angle": 135, "opacity": 1 } ``` ```json { "type": "image", "src": "background.png", "fit": "cover", "opacity": 1, "blur": 0 } ``` ```json { "type": "video", "src": "background.webm", "fit": "cover", "opacity": 1, "blur": 0, "muted": true } ``` - `src` is relative to the theme's `assets/` folder. - `fit` is `cover` (default) or `contain`. - `opacity` is clamped to `0`–`1`, `blur` to `0`–`40` pixels. - Background videos autoplay and loop. They are muted by default; set `muted` to `false` to play their audio. - Theme music (`audio`) cannot be combined with a video background; the editor disables music and the launcher ignores the `audio` entry in that case. - Prefer **WebM** for video backgrounds and video layers. It is supported by the launcher and keeps theme packages much smaller than MP4. MP4, MOV and M4V also work. ### Overlay ```json { "color": "#000000", "opacity": 0.2, "vignette": 0.35 } ``` `opacity` controls the flat dim layer and `vignette` darkens the edges. Both are clamped to `0`–`1`. ### Effects ```json { "type": "stars", "density": 40, "speed": 1, "color": "#ffd6f2" } ``` Supported types: `none`, `stars`, `snow`, `petals`, `bubbles`. - `density` is clamped to `0`–`120` particles. - `speed` is clamped to `0.2`–`3`. - Effects are disabled when the user turns on **Reduce animations**. ### Audio ```json { "src": "music.mp3", "loop": true } ``` `src` is relative to `assets/`. Music uses the launcher's volume control and is silent in the theme editor preview. Theme music cannot be combined with a `video` background. The editor disables the music controls while a video background is selected, and themes that contain both have their `audio` entry ignored. ### Typography `typography.body` changes the font used by the launcher UI. `typography.heading` changes headings such as the launcher title. `typography.mono` changes the monospace font used for paths, versions and telemetry labels; leave it out to keep the built-in Space Mono stack. ```json "typography": { "body": "Montserrat Variable", "heading": "Playfair Display Variable", "mono": "JetBrains Mono Variable" } ``` These families ship with the launcher through `@fontsource` and can be used without adding any files: | Family | Style | | --------------------------- | ------- | | `Sora Variable` | Sans | | `Montserrat Variable` | Sans | | `Bebas Neue` | Display | | `Playfair Display Variable` | Serif | | `Space Mono` | Mono | | `JetBrains Mono Variable` | Mono | Custom fonts can be packaged with the theme. The launcher generates the `@font-face` rules from `fonts`: ```json "fonts": [ { "family": "My Display Font", "src": "display.woff2", "weight": "400", "style": "normal" } ] ``` - `src` is relative to `assets/`. - Supported formats: WOFF2 (recommended), WOFF, TTF and OTF. - `weight` defaults to `400`; `style` defaults to `normal`. - Use the `family` value in `typography` and in text layers. The editor's **Fonts** tab browses the full Fontsource catalog (2,000+ families) and downloads the selected family, weight, style and subset as a WOFF2 into the theme's `assets/` folder. It adds the matching `fonts` entry automatically, so saved and exported themes stay self-contained. ### Icon set `iconSet` swaps the launcher's navigation, status, settings and theme-browser icons. The default is Lucide; Phosphor and Tabler are also bundled. ```json "iconSet": "phosphor" ``` | Value | Family | Character | | ---------- | -------- | ---------------------------------- | | `lucide` | Lucide | Clean geometric outlines (default) | | `phosphor` | Phosphor | Softer, rounded shapes | | `tabler` | Tabler | Crisp, technical outlines | Icon bodies ship with the launcher, so the setting never downloads anything at runtime. Unknown values fall back to Lucide, which keeps older launchers and hand-written themes compatible. The editor shows a live preview in **Theme → Icon set**, and the selected family is used across the launcher and its live home canvas. ### Freeform layers `elements` are rendered above the launcher UI, but only on the **Home** screen. The launcher canvas is a fixed **1000 × 650** coordinate space. Elements can extend the home screen with text, images, videos, shapes, icons, data readouts, gauges, tickers, Lottie animations and buttons. They are pointer-transparent by default so they never block buttons; set `interactive: true` to let a layer receive clicks and hovers from theme logic. Interactive layers sit above the UI and can block clicks inside their rectangle. The order of the `elements` array controls stacking: the last element is drawn on top. Themes can contain up to 100 layers. Every layer supports: | Field | Type | Notes | | ------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string | Unique within the theme | | `name` | string? | Optional editor label; does not affect rendering | | `type` | string | `text`, `data`, `image`, `video`, `shape`, `icon`, `repeater`, `gauge`, `ticker`, `lottie`, `button`, `path`, `particles`, `clock`, `countdown` or `svelte` | | `x`, `y` | number | Position in the 1000 × 650 stage | | `width` | number | 24–1000 | | `height` | number | 24–650 | | `rotation` | number | Degrees, `-360`–`360` | | `scale` | number | Legacy uniform scale fallback, `0.05`–`10` | | `scaleX` | number | Horizontal scale, `0.05`–`10` | | `scaleY` | number | Vertical scale, `0.05`–`10` | | `skewX` | number | Horizontal skew in degrees, `-89`–`89` | | `skewY` | number | Vertical skew in degrees, `-89`–`89` | | `flipX` | boolean | Mirror the layer horizontally | | `flipY` | boolean | Mirror the layer vertically | | `opacity` | number | `0`–`1` | | `hidden` | boolean | Keep the layer in the file but do not render it | | `locked` | boolean | Prevent moving/resizing the layer in the editor | | `interactive` | boolean | Opts into clicks and hovers from theme logic | | `groupId` | string? | Group that contains this layer | | `filters` | object? | Per-layer CSS filters; see **Groups and filters** | | `mask` | object? | Shape or image clip; see **Masks** | | `cssClasses` | string? | Space-separated classes for the layer wrapper | #### Text ```json { "id": "greeting", "type": "text", "text": "Welcome back!", "x": 360, "y": 220, "width": 420, "height": 90, "fontFamily": "Bebas Neue", "fontSize": 42, "fontWeight": 600, "fontStyle": "normal", "color": "#ffffff", "align": "center", "verticalAlign": "center", "lineHeight": 1.2, "letterSpacing": 0, "textDecoration": "none", "textTransform": "none", "fillMode": "solid", "outlineWidth": 0, "outlineColor": "#000000", "shadowColor": "#000000", "shadowBlur": 0, "shadowOffsetX": 0, "shadowOffsetY": 0 } ``` `align` is `left`, `center` or `right`; `verticalAlign` is `top`, `center` or `bottom`. Font size is clamped to `6`–`240`. Text layers support the full visual styling set: | Field | Type | Notes | | ---------------- | ------ | --------------------------------------------------------------- | | `fontStyle` | string | `normal` or `italic` | | `textDecoration` | string | `none`, `underline`, `line-through` or `underline line-through` | | `textTransform` | string | `none`, `uppercase`, `lowercase` or `capitalize` | | `fillMode` | string | `solid` or `gradient` | | `gradientFrom` | string | Gradient start color | | `gradientTo` | string | Gradient end color | | `gradientAngle` | number | Degrees, `0`–`360`; `90` is left to right | | `outlineWidth` | number | Pixels, `0`–`20`; `0` disables the outline | | `outlineColor` | string | Outline color | | `shadowColor` | string | Text shadow color | | `shadowBlur` | number | Pixels, `0`–`40` | | `shadowOffsetX` | number | Pixels, `-40`–`40` | | `shadowOffsetY` | number | Pixels, `-40`–`40` | Gradient fills use `gradientFrom` and `gradientTo`; `color` remains the fallback for solid fills and is used for text decoration when no gradient is active. Text outlines are drawn behind the fill, so gradients and outlines can be combined. #### Dynamic text Text layers can show live rule variables with `{name}` placeholders. Variables are shared by every rule and text layer in the theme. ```json { "type": "text", "text": "Clicks: {clicks}\nPlayer: {player}", "id": "counter" } ``` ```js clicks += 1; if (clicks >= 3) { player = 'Ready!'; } ``` The theme can declare starting values for its variables. This is optional; any variable without an entry starts at `0`. ```json "variables": { "clicks": 0, "player": "Guest", "ready": false } ``` Every valid placeholder starts with its declared value when the theme loads, then updates whenever a script or builder action changes that variable. Values may be numbers, strings or booleans, and variables that are only read by rules or scripts can be seeded here as well. Numbers, strings and booleans are inserted as plain text. Reserved names such as `{screen}` and malformed placeholders stay visible instead of rendering a value. In the editor, the text inspector lists known variables and inserts the placeholder at the cursor, and **Theme → Variables** sets each variable's starting value; clearing a field falls back to `0`. #### Built-in clock The engine also exposes read-only local clock values. They refresh once per second, so a text layer or script can display the live time without declaring any variables. Conditions also read the current clock whenever a rule fires. | Placeholder | Value | | --------------- | ------------------------------------------ | | `{time}` | 24-hour time, e.g. `21:05` | | `{time12}` | 12-hour time with AM/PM, e.g. `9:05 PM` | | `{timeSeconds}` | 24-hour time with seconds, e.g. `21:05:07` | | `{hour}` | Hour from `0` to `23` | | `{minute}` | Minute from `0` to `59` | | `{second}` | Second from `0` to `59` | | `{dayPeriod}` | `AM` or `PM` | ```html

{time12}

LOCAL // {timeSeconds}

``` They are available to conditions and scripts too, which makes day/night themes simple: ```js if (hour >= 18 || hour < 6) { showGroup('night'); hideGroup('day'); } ``` Conditions are evaluated when their rule's trigger fires, so pair a time-based condition with a **timer** trigger to re-check it while the launcher is open. For example, a rule with `trigger: { "type": "timer", "interval": 10 }` and a condition on `hour` switches the theme at sunset or sunrise without restarting. The helper actions **Show group** / **Hide group** make this easy to build in the rule editor; the **Clock** quick-pick in a variable condition fills in `time`, `hour`, `minute`, `second` or `dayPeriod` for you. The clock names are reserved. Assigning to `time`, `hour` or any other clock name is a script error, and they are not listed in **Theme → Variables**. They appear in the text inspector's insert row and in script completion. #### Image and video ```json { "id": "logo", "type": "image", "src": "logo.png", "x": 700, "y": 420, "width": 220, "height": 140, "fit": "contain", "radius": 18, "tint": "", "opacity": 1 } ``` `tint` repaints the image's alpha silhouette with a solid color. It is the simplest way to make a monochrome SVG logo follow the theme accent; leave it out or set it to an empty string to keep the original colors. ```json { "id": "ambient", "type": "video", "src": "ambient.webm", "x": 0, "y": 0, "width": 1000, "height": 650, "fit": "cover", "opacity": 0.35 } ``` Video layers autoplay and loop. They are muted by default; set `muted` to `false` to play their audio. WebM is recommended for size. Use an `opacity` below `1` if the video should blend into the launcher UI. #### Shape ```json { "id": "glow", "type": "shape", "shape": "ellipse", "x": 680, "y": 60, "width": 260, "height": 260, "fill": "#ff006e", "opacity": 0.18, "borderWidth": 0, "borderColor": "#ffffff" } ``` `shape` is `rectangle`, `ellipse`, `line`, `polygon`, `star` or `arc`. `radius` rounds rectangle corners and `cornerRadii` (top-left, top-right, bottom-right, bottom-left) overrides it per corner. `points` sets polygon sides and star points (`3`–`24`), and `innerRadius` sets the star's inner radius (`0.1`–`0.95`). An `arc` draws a ring segment instead of a filled shape. Angles start at 12 o'clock and run clockwise; `endAngle` may wrap past `360` and a full `360` span becomes a ring. `thickness` is the stroke width in stage pixels and `rounded` controls the end caps. ```json { "id": "dial", "type": "shape", "shape": "arc", "x": 700, "y": 80, "width": 180, "height": 180, "startAngle": -120, "endAngle": 120, "thickness": 10, "rounded": true, "fillMode": "gradient", "gradientFrom": "#ff006e", "gradientTo": "#7c3aed" } ``` Fill can be a solid color or a gradient: ```json { "id": "sunburst", "type": "shape", "shape": "star", "x": 120, "y": 120, "width": 220, "height": 220, "points": 8, "innerRadius": 0.42, "fillMode": "gradient", "gradientFrom": "#ffd166", "gradientTo": "#ff006e", "gradientAngle": 135, "opacity": 0.9 } ``` `borderStyle` accepts `solid`, `dashed` or `dotted`, and `backdropBlur` adds a frosted-glass blur behind the shape (`0`–`60` pixels). Keep the fill partially transparent to see the blur. #### Icon An icon layer draws a semantic icon from the theme's icon set, so switching `iconSet` changes every icon layer with the rest of the launcher. ```json { "id": "star", "type": "icon", "icon": "music", "x": 720, "y": 80, "width": 64, "height": 64, "color": "#ffd6f2", "scale": 100 } ``` `scale` is a percentage of the layer's shortest side (`10`–`100`). The available names are the ones listed by **Theme → Icon** in the editor. #### Data layer A data layer is a text layer whose content comes from the launcher instead of static copy. Use `{value}` in `text` as the placeholder. ```json { "id": "player", "type": "data", "field": "user.name", "text": "Welcome, {value}!", "x": 360, "y": 180, "width": 420, "height": 60, "fontSize": 26, "color": "#ffffff" } ``` Fields: `user.name`, `user.country`, `user.pp`, `user.rank`, `user.plays`, `user.accuracy`, `user.playtime`, `launcher.version`, `osu.build`, `osu.stream`, `server.ping`, `server.friends`, `theme.name`, `theme.author`, `theme.version`, `screen`, `clock.time`, `clock.time12` and `clock.date`. Player stat fields accept `mode`: `osu`, `taiko`, `catch` or `mania`. Unknown or signed-out values render as an empty string. A data layer accepts every text styling field (`fontFamily`, `fontSize`, `fillMode`, `outlineWidth`, shadows and so on). #### Repeater A repeater tiles an image or an icon across the layer bounds. ```json { "id": "sparkles", "type": "repeater", "source": "icon", "icon": "music", "x": 120, "y": 480, "width": 300, "height": 120, "tileWidth": 28, "tileHeight": 28, "gapX": 14, "gapY": 14, "color": "#ffffff" } ``` `source` is `image` or `icon`. Image repeaters use `src`, `radius` and `fit` (`cover` inside each tile). Leave `columns` and `rows` at `0` to fill the bounds; explicit counts are clamped to `60`. At most 240 tiles are drawn. #### Gauge A gauge renders a bar or a ring from a `0`–`1` value. Bind it to a theme variable so logic rules can animate it, or leave `variable` out and use the static value. ```json { "id": "progress", "type": "gauge", "mode": "ring", "variable": "sync", "x": 760, "y": 420, "width": 120, "height": 120, "trackColor": "#000000", "fillColor": "#ff006e", "thickness": 10, "rounded": true, "label": "{percent}%" } ``` `label` supports `{percent}`, `{value}` and any rule variable. `thickness` is the ring stroke width in pixels; the bar fills the layer height. #### Ticker A ticker scrolls a single line of text horizontally. ```json { "id": "now-playing", "type": "ticker", "text": "Now playing · Your favourite track · ", "x": 120, "y": 560, "width": 420, "height": 48, "fontSize": 20, "color": "#ffffff", "speed": 18, "gap": 48 } ``` `speed` is the number of seconds for one loop. The track is duplicated so the loop is seamless, and animation stops when the system asks for reduced motion. #### Lottie animation A Lottie layer plays a JSON animation from the theme's `assets` folder. It scales crisply and is usually far smaller than a WebM. ```json { "id": "crest", "type": "lottie", "src": "crest.json", "x": 720, "y": 60, "width": 200, "height": 200, "loop": true, "autoplay": true, "speed": 1 } ``` `speed` is clamped to `0.1`–`4`. The exported preview image renders the first frame; the launcher renders the live animation. #### Vector path A `path` layer draws custom SVG path data as a scalable shape. Author the path inside a **0–100** coordinate box; it is stretched to the layer rectangle. M, L, H, V, C, S, Q, T, A and Z commands are supported, and anything outside path grammar is stripped when the theme loads. ```json { "id": "wave", "type": "path", "path": "M 0 70 C 20 20 35 95 55 55 C 72 22 86 40 100 10 L 100 100 L 0 100 Z", "x": 0, "y": 470, "width": 700, "height": 180, "fillMode": "gradient", "gradientFrom": "#ff006e", "gradientTo": "#7c3aed", "gradientAngle": 90, "stroke": "#ffffff", "strokeWidth": 2, "strokeStyle": "solid", "strokeLinecap": "round" } ``` Set `stroke` to an empty string for a fill-only path. `strokeStyle` accepts `solid`, `dashed` or `dotted`, and `strokeLinecap` accepts `butt`, `round` or `square`. #### Particles A particle field animates inside its rectangle without any assets. The presets cover the most common ambient effects, and the layer respects the system's reduced-motion setting. ```json { "id": "sparkle-field", "type": "particles", "preset": "sparkles", "x": 520, "y": 90, "width": 420, "height": 360, "density": 42, "size": 7, "speed": 1, "color": "#ffe9a8", "color2": "#ff006e", "wind": 0.2, "fade": true } ``` | Field | Type | Notes | | --------- | ------- | ------------------------------------------------------------- | | `preset` | string | `sparkles`, `snow`, `petals`, `bubbles`, `embers`, `confetti` | | `density` | number | Particle count, `4`–`120` | | `speed` | number | Animation speed multiplier, `0.1`–`3` | | `size` | number | Base particle size in stage pixels, `1`–`24` | | `color` | string | Primary color | | `color2` | string | Secondary color; particles alternate between both | | `wind` | number | Horizontal drift, `-1` (left) to `1` (right) | | `fade` | boolean | Fade particles at the top and bottom edges (default `true`) | #### Clock A clock layer shows the viewer's local time, either as text or as an analog dial. It ticks once per second while it is visible. ```json { "id": "local-time", "type": "clock", "mode": "digital", "x": 40, "y": 500, "width": 300, "height": 110, "hour12": false, "showSeconds": true, "showDate": true, "label": "Local time", "fontFamily": "Sora Variable", "fontSize": 42, "fontWeight": 700, "color": "#ffffff", "accentColor": "#ff006e", "align": "center" } ``` `mode` is `digital` or `analog`. `hour12`, `showSeconds` and `showDate` affect the digital clock; the analog dial always uses local hours and shows the second hand unless `showSeconds` is `false`. `accentColor` colors the second hand, dial details and the date. #### Countdown A countdown layer ticks towards an ISO date-time using a template. It shares the clock tick and needs no logic rule. ```json { "id": "release", "type": "countdown", "target": "2027-01-01T00:00:00Z", "text": "{days}d {hours}h {minutes}m {seconds}s", "finishedText": "Happy new year!", "x": 60, "y": 420, "width": 380, "height": 80, "fontSize": 34, "color": "#ffffff", "align": "left" } ``` The template supports `{days}`, `{hours}`, `{minutes}` and `{seconds}`. Hours, minutes and seconds are zero-padded. Once the target passes, `finishedText` is shown instead. An empty or invalid `target` displays zeroes. #### Button A button layer is a real launcher control. It receives clicks even though the rest of the layer stack is pointer-transparent, and it is above the built-in UI. ```json { "id": "open-themes", "type": "button", "label": "Browse themes", "icon": "themes", "x": 360, "y": 480, "width": 240, "height": 52, "action": { "type": "navigate", "screen": "themes" }, "background": "#ff006e", "color": "#ffffff", "hoverBackground": "#ff4d94", "radius": 12 } ``` `action` is one of: | Action | Shape | | ---------- | ------------------------------------------ | | `navigate` | `{ "type": "navigate", "screen": "home" }` | | `launch` | `{ "type": "launch" }` | | `url` | `{ "type": "url", "url": "https://…" }` | External URLs always open through the launcher's confirmation dialog, which shows the full address first. A `url` action must use `http` or `https`; the theme check reports anything else as an error. #### Custom Svelte layer A `svelte` layer is a self-contained Svelte 5 component compiled by the launcher at runtime. It fills the layer rectangle and can render any markup, SVG or canvas content, use runes, and import from Svelte's runtime modules. ```json { "id": "welcome", "type": "svelte", "x": 360, "y": 200, "width": 360, "height": 190, "interactive": true, "source": "\n\n
Score: {variables.score}
\n\n\n" } ``` The component receives these reactive props: | Prop | Value | | ----------- | ----------------------------------------------------------------------- | | `variables` | Live theme variable values. Logic rule changes update the component. | | `screen` | The current launcher screen (custom layers render on Home today). | | `layer` | `{ id, name, width, height }` for this layer. | | `theme` | `{ name, author, accentColor }`. | | `asset` | `asset('image.png')` resolves a file inside the theme `assets/` folder. | ```svelte

Score: {variables.score ?? 0}

``` The editor provides a Monaco source pane with Svelte/JavaScript highlighting, completions for props, runes and theme variables, and inline compiler errors. The source is **plain JavaScript**; TypeScript in `