# Using within charts (/developers/pinets/using-within-charts)



![Vela-PineTS — Pine Script indicators and strategies for Vela™](/images/pinets/vela-pinets-banner.png)

PineTS runs Pine Script and returns plot series as JavaScript — useful for bots, alerts, and pipelines. To **draw those indicators on a chart**, pair PineTS with [Vela™](/vela) through **Vela-PineTS** (`@luxalgo/vela-pinets`).

Vela™ ships no scripting engine and stays Apache-2.0. Vela-PineTS is the official Pine addon: it implements Vela™'s public `ScriptingEngine` port on top of the PineTS runtime, so `addIndicator()` can compile and plot native Pine (or PineTS) source.

## Install [#install]

```bash
npm install @luxalgo/vela @luxalgo/vela-pinets pinets
```

`@luxalgo/vela` and `pinets` are peers of Vela-PineTS. You need all three: the chart, the bridge, and the runtime.

## Register the engine and add a script [#register-the-engine-and-add-a-script]

Register the engine under the `pine` language id, then pass a script. Calls that omit `language` still resolve to Pine:

```ts
import { Vela } from '@luxalgo/vela';
import { PineEngine } from '@luxalgo/vela-pinets';

const chart = new Vela('#chart', { symbol: 'BTCUSDT', timeframe: '60', live: true });
chart.registerEngine('pine', new PineEngine());

chart.addIndicator(`//@version=5
indicator("EMA 20", overlay=true)
plot(ta.ema(close, 20), color=color.orange, linewidth=2)`);
```

`request.security` (higher/lower timeframes, other symbols) resolves through Vela™'s own cached data feed — the engine never fetches candles itself.

## Keep the chart responsive [#keep-the-chart-responsive]

Both engines have identical Pine semantics. Use the worker when a heavy script must not block painting:

| Export             | Where scripts run | Use it when                              |
| ------------------ | ----------------- | ---------------------------------------- |
| `PineEngine`       | the main thread   | simplest setup; light scripts            |
| `PineWorkerEngine` | a Web Worker      | heavy scripts must never block the chart |

```ts
import { PineWorkerEngine } from '@luxalgo/vela-pinets';

chart.registerEngine('pine', new PineWorkerEngine());
```

The worker source is inlined into the addon and spawned from a Blob URL. Under a Content-Security-Policy that blocks `blob:`, host the worker file yourself and pass `new PineWorkerEngine({ workerUrl: '/vela-pine-worker.js' })`.

## Workspace and indicator manifests [#workspace-and-indicator-manifests]

The [workspace](/vela/user/workspace) takes engine **factories** (one instance per chart) and an indicator manifest — inline JSON, a URL, or an async loader:

```ts
import { VelaWorkspace } from '@luxalgo/vela/workspace';
import { PineWorkerEngine } from '@luxalgo/vela-pinets';

new VelaWorkspace('#chart', {
  layout: false,
  symbol: 'BTCUSDT',
  timeframe: '60',
  live: true,
  engines: { pine: () => new PineWorkerEngine() },
  indicators: '/indicators.json',
});
```

To wire Pine in once for every chart afterwards, call `registerDefaultEngine` from `@luxalgo/vela/plugin`:

```ts
import { registerDefaultEngine } from '@luxalgo/vela/plugin';
import { PineWorkerEngine } from '@luxalgo/vela-pinets';

registerDefaultEngine('pine', () => new PineWorkerEngine());
```

An explicit `engines` entry still wins for its language.

## Strategies [#strategies]

A `strategy()` script runs through the same engine as an indicator. PineTS's broker emulator computes the ledger; Vela-PineTS emits **one marker per order fill** as `IndicatorModel.trades`, which Vela™ paints on the price pane.

```ts
chart.addIndicator(`//@version=5
strategy("EMA cross", overlay=true)
fast = ta.ema(close, 9)
slow = ta.ema(close, 21)
if ta.crossover(fast, slow)
    strategy.entry("Long", strategy.long)
if ta.crossunder(fast, slow)
    strategy.close("Long")`);
```

Mutable `indicator()` / `strategy()` arguments (`initial_capital`, `precision`, …) show up on the settings dialog's **Properties** tab. Override them at add time with `addIndicator({ props })` or later with `handle.setProps()`.

## Script tag / CDN [#script-tag--cdn]

Load Vela™ first so the addon resolves `@luxalgo/vela` to the page's `window.Vela` instead of bundling a second copy:

```html
<script src="vela.global.js"></script>
<script src="vela-pinets.global.js"></script>
<script>
  const chart = new Vela.Vela('#chart', { data: bars, timeframe: '60' });
  chart.registerEngine('pine', new VelaPinets.PineEngine());
</script>
```

## How the pieces fit [#how-the-pieces-fit]

| Package                                                                      | Role                                                                               | License    |
| ---------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ---------- |
| [`pinets`](https://www.npmjs.com/package/pinets)                             | Pine Script runtime — transpile and execute in Node, Deno, Bun, or the browser     | AGPL-3.0   |
| [`@luxalgo/vela-pinets`](https://www.npmjs.com/package/@luxalgo/vela-pinets) | **Vela-PineTS** — the `ScriptingEngine` that paints PineTS output on a Vela™ chart | AGPL-3.0   |
| [`@luxalgo/vela`](https://www.npmjs.com/package/@luxalgo/vela)               | The chart — candles, drawings, panes. No Pine code                                 | Apache-2.0 |

Use PineTS alone when you want plot values, alerts, or a backtest ledger in your own process. Add Vela-PineTS when you want those same scripts on a Vela™ chart.

Installing the addon brings the AGPL obligations into *your* deployment. If you cannot take them on, write an engine for the language you need against Vela™'s port instead.

## Related [#related]

* [Vela™ scripting engines](/vela/user/scripting-engines) — engines, licensing, and writing your own.
* [Vela™ workspace](/vela/user/workspace) — multi-chart grid, manifests, and persistence.
* [Getting started](/developers/pinets/getting-started) — run PineTS without a chart.
* [Vela-PineTS on GitHub](https://github.com/LuxAlgo/Vela-pinets)
