Built on HTML5 Canvas for smooth and dynamic chart rendering. Can be helpful for visualizing financial data like stocks, forex, and cryptocurrencies.
1. Import the DXCharts Lite library into your document.
<script src="./dxchart.min.js"></script>
2. Create an empty DIV that serves as the container for your financial chart.
<div id="chart_container"></div>
3. Create a new instance of the DXCharts Lite.
const container = document.getElementById("chart_container");
const chartInstance = DXChart.createChart(container); 4. Pass your own data into the chart.
chartInstance.chartComponent.setMainSeries({
...
}); 5. Available configs to customize the chart.
const chartInstance = DXChart.createChart(container,{
// shows promp link
devexpertsPromoLink: true,
useUTCTimeOverride: false,
shortDays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
shortMonths: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
rtl: false,
scale: {
keepZoomXOnYAxisChange: true,
auto: true,
zoomToCursor: false,
lockPriceToBarRatio: false,
autoScaleOnCandles: true,
autoScaleDisableOnDrag: {
enabled: true,
edgeAngle: Math.PI / 15,
yDiff: 80,
},
inverse: false,
zoomSensitivity: 0.25,
defaultViewportItems: 100,
},
// local timezone
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
components: {
chart: {
// candle, bar, area and others.
type: 'candle',
showCandlesBorder: true,
showActiveCandlesBorder: true,
showWicks: true,
candleLineWidth: 1,
lineWidth: 1,
areaLineWidth: 1,
barLineWidth: 1,
// minimum candle width in canvas units - not real pixels! for mac with DPR=2 it will be equal 1 pixel
minWidth: 0.5,
minCandles: 10,
candlePaddingPercent: 0.25,
highlightActiveCandle: true,
cursor: 'default',
selectedWidth: 3,
minCandlesOffset: 2,
defaultZoomCandleWidth: 7,
zoomStep: 0,
histogram: {
barCapSize: 1,
},
},
yAxis: {
// 'regular', 'percent', 'logarithmic'
type: 'regular',
visible: true,
labelHeight: 23,
zeroPercentLine: true,
customScale: true,
customScaleDblClick: true,
align: 'right',
fontSize: 12,
fontFamily: MAIN_FONT,
cursor: 'ns-resize',
resizeDisabledCursor: 'default',
labelBoxMargin: {
top: 4,
bottom: 4,
end: 8,
start: 10,
},
typeConfig: {
badge: {
rounded: true,
paddings: {
top: 4,
bottom: 4,
end: 4,
start: 4,
},
},
plain: {},
rectangle: {
rounded: false,
paddings: {
top: 4,
bottom: 4,
end: 4,
start: 4,
},
},
},
labels: {
descriptions: false,
settings: {
lastPrice: {
mode: 'label',
type: 'badge',
},
countdownToBarClose: {
mode: 'none',
type: 'rectangle',
},
},
},
},
xAxis: {
visible: true,
formatsForLabelsConfig: {
lessThanSecond: 'HH:mm:ss',
second_1: 'HH:mm:ss',
minute_1: 'HH:mm',
minute_5: 'HH:mm',
minute_30: 'HH:mm',
hour_1: 'HH:mm',
day_1: 'dd.MM',
month_1: 'MMM',
year_1: 'YYYY',
},
fontSize: 12,
fontFamily: MAIN_FONT,
cursor: 'ew-resize',
padding: {
top: 8,
bottom: 16,
},
fontStyle: '',
},
events: {
visible: false,
eventsVisibility: {
'conference-calls': true,
dividends: true,
splits: true,
earnings: true,
},
height: 20,
cursor: 'default',
xAxisLabelFormat: [
{
format: 'd MMM',
},
],
icons: {
earnings: {
normal: '',
hover: '',
},
},
},
offsets: {
visible: true,
right: 10,
top: 10,
bottom: 20,
left: 0,
},
waterMark: {
visible: false,
fontFamily: 'Open Sans, sans-serif',
firstRowFontSize: 80,
firstRowBottomPadding: 10,
secondRowFontSize: 40,
secondRowBottomPadding: 25,
thirdRowFontSize: 40,
thirdRowBottomPadding: 15,
position: 'center',
offsetX: 20,
offsetY: 20,
logoWidth: 20,
logoHeight: 20,
},
highLow: { visible: false, font: '12px sans-serif' },
highlights: {
visible: false,
fontFamily: 'Open Sans',
fontSize: 13,
border: {
width: 1,
dash: [8, 4],
},
},
crossTool: {
type: 'cross-and-labels',
discrete: false,
magnetTarget: 'none',
lineDash: [4, 6],
xAxisLabelFormat: [
{
format: 'dd.MM.YYYY',
showWhen: {
periodMoreThen: 84600000,
},
},
{
format: 'dd.MM.YYYY HH:mm',
showWhen: {
periodLessThen: 84600000,
periodMoreThen: 6000,
},
},
{
format: 'dd.MM.YYYY HH:mm:ss',
showWhen: {
periodLessThen: 6000,
},
},
],
xLabel: {
padding: {
top: 4,
bottom: 4,
right: 8,
left: 8,
},
margin: {
top: 4,
},
},
yLabel: {
padding: {
top: 4,
bottom: 4,
end: 4,
start: 4,
},
type: 'badge',
},
},
grid: {
visible: true,
horizontal: false,
vertical: true,
width: 1,
dash: [0, 0],
color: '#FFFFFF',
},
volumes: {
visible: true,
showSeparately: false,
valueLines: 15,
barCapSize: 1,
volumeBarSpace: 0,
volumeFillColor: '#FFFFFF',
},
navigationMap: {
visible: false,
allCandlesHistory: 10,
minSliderWindowWidth: ,
timeLabels: {
visible: false,
dateFormat: 'dd.MM.YYYY HH:mm',
fontFamily: 'Open Sans',
fontSize: 13,
padding: {
x: 10,
y: 1,
},
},
minSliderWindowWidth: 10,
cursors: {
chart: 'default',
buttonLeft: 'pointer',
buttonRight: 'pointer',
leftResizer: 'ew-resize',
rightResizer: 'ew-resize',
slider: 'grab',
},
knots: {
height: 35,
width: 7,
border: 0,
lineWidth: 1,
},
},
baseline: {
cursor: 'ns-resize',
dragZone: 3,
height: 1,
},
paneResizer: {
cursor: 'ns-resize',
height: 1,
visible: true,
fixedMode: false,
dragZone: 3,
},
},
colors: {
candleTheme: {
upColor: 'rgba(77,153,83,1)',
downColor: 'rgba(217,44,64,1)',
noneColor: 'rgba(255,255,255,1)',
upWickColor: 'rgba(77,153,83,1)',
downWickColor: 'rgba(217,44,64,1)',
noneWickColor: 'rgba(255,255,255,1)',
borderOpacity: 1,
},
barTheme: { upColor: 'rgba(77,153,83,1)', downColor: 'rgba(217,44,64,1)', noneColor: 'rgba(255,255,255,1)' },
lineTheme: { upColor: 'rgba(77,153,83,1)', downColor: 'rgba(217,44,64,1)', noneColor: 'rgba(255,255,255,1)' },
chartAreaTheme: {
backgroundMode: 'regular',
backgroundColor: 'rgba(20,20,19,1)',
backgroundGradientTopColor: 'red',
backgroundGradientBottomColor: 'blue',
axisColor: 'rgba(128,128,128,1)',
gridColor: 'rgba(37,37,36,1)',
},
scatterPlot: { mainColor: 'rgba(255,255,255,1)' },
areaTheme: {
lineColor: 'rgba(127,120,214,1)',
startColor: 'rgba(169,38,251,1)',
stopColor: 'rgba(169,38,251,0.8)',
},
baseLineTheme: {
lowerSectionStrokeColor: 'rgba(217,44,64,1)',
upperSectionStrokeColor: 'rgba(77,153,83,1)',
lowerSectionFillColor: 'rgba(217, 44, 64, 0.07)',
upperSectionFillColor: 'rgba(77, 153, 83, 0.07)',
baselineColor: 'rgba(55,55,54,1)',
},
histogram: {
upCap: 'rgba(77,153,83,1)',
upBottom: 'rgba(77,153,83,0.1)',
upBright: 'rgba(77,153,83,0.4)',
downCap: 'rgba(217,44,64,1)',
downBottom: 'rgba(217,44,64,0.1)',
downBright: 'rgba(217,44,64,0.4)',
noneCap: 'rgba(255,255,255,1)',
noneBottom: 'rgba(255,255,255,0.1)',
noneBright: 'rgba(255,255,255,0.4)',
},
crossTool: {
lineColor: 'rgba(107,96,86,1)',
labelBoxColor: 'rgba(107,96,86,1)',
labelTextColor: 'rgba(255,255,255,1)',
},
waterMarkTheme: {
firstRowColor: 'rgba(255,255,255,0.2)',
secondRowColor: 'rgba(255,255,255,0.2)',
thirdRowColor: 'rgba(255,255,255,0.2)',
},
highlights: {
NO_TRADING: { border: 'rgba(107,96,86,1)', background: 'transparent', label: 'transparent' },
AFTER_MARKET: { border: 'rgba(107,96,86,1)', background: 'rgba(38, 251, 149, 0.05)', label: 'transparent' },
PRE_MARKET: { border: 'rgba(107,96,86,1)', background: 'rgba(255, 170, 0, 0.05)', label: 'transparent' },
REGULAR: { border: 'rgba(107,96,86,1)', background: 'transparent', label: 'transparent' },
},
activeCandleTheme: {
upColor: 'rgba(98,201,93,1)',
downColor: 'rgba(255,47,47,1)',
noneColor: 'rgba(255,255,255,1)',
upWickColor: 'rgba(98,201,93,1)',
downWickColor: 'rgba(255,47,47,1)',
noneWickColor: 'rgba(255,255,255,1)',
borderOpacity: 0.5,
},
volume: {
downBarColor: 'rgba(99,30,37,1)',
upBarColor: 'rgba(42,72,44,1)',
noneBarColor: 'rgba(255,255,255,0.4)',
upCapColor: 'rgba(42,72,44,1)',
downCapColor: 'rgba(99,30,37,1)',
noneCapColor: 'rgba(255,255,255,0.4)',
},
highLowTheme: { highColor: 'rgba(223,222,223,1)', lowColor: 'rgba(223,222,223,1)' },
instrumentInfo: { textColor: '#aeb1b3' },
paneResizer: {
lineColor: 'rgba(55,55,54,1)',
bgColor: 'rgba(20,20,19,1)',
bgHoverColor: 'rgba(55,55,54,0.6)',
},
events: {
earnings: { color: 'rgba(217,44,64,1)' },
dividends: { color: 'rgba(169,38,251,1)' },
splits: { color: 'rgba(244,187,63,1)' },
'conference-calls': { color: 'rgba(48,194,97,1)' },
},
secondaryChartTheme: [
{
lineTheme: {
upColor: 'rgba(226,61,25,1)',
downColor: 'rgba(226,61,25,1)',
noneColor: 'rgba(226,61,25,1)',
},
areaTheme: {
lineColor: 'rgba(226,61,25,1)',
startColor: 'rgba(226,61,25,0.8)',
stopColor: 'rgba(226,61,25,0)',
},
},
{
lineTheme: {
upColor: 'rgba(250,191,64,1)',
downColor: 'rgba(250,191,64,1)',
noneColor: 'rgba(250,191,64,1)',
},
areaTheme: {
lineColor: 'rgba(250,191,64,1)',
startColor: 'rgba(250,191,64,0.8)',
stopColor: 'rgba(250,191,64,0)',
},
},
{
lineTheme: {
upColor: 'rgba(169,38,251,1)',
downColor: 'rgba(169,38,251,1)',
noneColor: 'rgba(169,38,251,1)',
},
areaTheme: {
lineColor: 'rgba(169,38,251,1)',
startColor: 'rgba(169,38,251,0.8)',
stopColor: 'rgba(169,38,251,0)',
},
},
{
lineTheme: {
upColor: 'rgba(77,211,240,1)',
downColor: 'rgba(77,211,240,1)',
noneColor: 'rgba(77,211,240,1)',
},
areaTheme: {
lineColor: 'rgba(77,211,240,1)',
startColor: 'rgba(77,211,240,0.8)',
stopColor: 'rgba(77,211,240,0)',
},
},
{
lineTheme: {
upColor: 'rgba(59,203,91,1)',
downColor: 'rgba(59,203,91,1)',
noneColor: 'rgba(59,203,91,1)',
},
areaTheme: {
lineColor: 'rgba(59,203,91,1)',
startColor: 'rgba(59,203,91,0.8)',
stopColor: 'rgba(59,203,91,0)',
},
},
],
yAxis: {
backgroundColor: 'transparent',
backgroundHoverColor: 'rgba(20,20,19,1)',
labelBoxColor: 'rgba(20,20,19,1)',
labelTextColor: 'rgba(128,128,128,1)',
labelInvertedTextColor: 'rgba(20,20,19,1)',
rectLabelTextColor: 'rgba(255,255,255,1)',
rectLabelInvertedTextColor: 'rgba(20,20,19,1)',
zeroPercentLine: 'rgba(55,55,54,1)',
},
labels: {
lastPrice: {
textNegative: 'rgba(255,255,255,1)',
textPositive: 'rgba(255,255,255,1)',
textSelected: 'rgba(0,0,0,1)',
boxNegative: 'rgba(217,44,64,1)',
boxPositive: 'rgba(77,153,83,1)',
boxSelected: 'rgba(255,255,255,1)',
},
countdownToBarClose: {
textNegative: 'rgba(255,255,255,1)',
textPositive: 'rgba(255,255,255,1)',
textSelected: 'rgba(255,255,255,1)',
boxNegative: 'rgba(217,44,64,1)',
boxPositive: 'rgba(77,153,83,1)',
boxSelected: 'rgba(255,255,255,1)',
},
highLow: {
high: { boxColor: 'rgba(107,96,86,1)', textColor: 'rgba(255,255,255,1)', descriptionText: 'High' },
low: { boxColor: 'rgba(107,96,86,1)', textColor: 'rgba(255,255,255,1)', descriptionText: 'Low' },
},
bidAsk: {
bid: { boxColor: 'rgba(77,153,83,1)', textColor: 'rgba(255,255,255,1)', descriptionText: 'Bid' },
ask: { boxColor: 'rgba(217,44,64,1)', textColor: 'rgba(255,255,255,1)', descriptionText: 'Ask' },
},
prePostMarket: {
post: { boxColor: 'rgba(38,251,149,1)', textColor: 'rgba(20,20,19,1)', descriptionText: 'Post' },
pre: { boxColor: 'rgba(255,170,0,1)', textColor: 'rgba(20,20,19,1)', descriptionText: 'Pre' },
},
prevDayClose: { boxColor: 'rgba(107,96,86,1)', textColor: 'rgba(255,255,255,1)' },
},
xAxis: {
backgroundColor: 'transparent',
labelTextColor: 'rgba(128,128,128,1)',
},
navigationMap: {
backgroundColor: 'transparent',
buttonColor: 'rgba(255,255,255,0.1)',
buttonArrowColor: 'rgba(212,212,211,1)',
knotColor: 'rgba(255,255,255,0.1)',
knotLineColor: 'rgba(212,212,211,1)',
sliderColor: 'rgba(255,255,255,0.08)',
knotBorderColor: '#0b0d1a',
timeLabelsTextColor: 'rgba(128,128,128,1)',
mapColor: 'rgba(255,255,255,0.1)',
mapFillColor: 'rgba(255,255,255,0.1)',
mapGradientTopColor: 'rgba(255,255,255,0.1)',
mapGradientBottomColor: 'rgba(255,255,255,0.1)',
},
},
animation: {
moveDuration: 1000,
candleDuration: 200,
paneResizer: {
bgMode: true,
enabled: true,
duration: 40,
},
yAxis: {
background: {
enabled: false,
duration: 40,
},
},
},
drawingOrder: [
'OVER_SERIES_CLEAR',
'MAIN_CLEAR',
'SERIES_CLEAR',
'GRID',
'X_AXIS',
'Y_AXIS',
'UNDERLAY_VOLUMES_AREA',
'VOLUMES',
'DATA_SERIES',
'DRAWINGS',
'WATERMARK',
'N_MAP_CHART',
'EVENTS',
],
}); 6. API methods:
// chartComponent chartInstance.data.doActivate() chartInstance.data.registerDefaultCandlesTransformers() registerCandlesTransformer(chartType: keyof BarTypes, transformer: VisualCandleCalculator) chartInstance.data.registerLastCandleLabelHandler(chartType: keyof BarTypes, handler: LastCandleLabelHandler) chartInstance.data.registerCandlesWidthCalculator(chartType: keyof BarTypes, calculator: CandleWidthCalculator) chartInstance.data.registerDefaultDataSeriesDrawers chartInstance.data.setChartType(type: keyof BarTypes) chartInstance.data.resetChartScale() chartInstance.data.setShowWicksisShow(boolean) chartInstance.data.setMainSeries(CandleSeries) chartInstance.data.setSecondarySeriesseries(CandleSeries) chartInstance.data.setAllSeries(mainSeries: CandleSeries, secondarySeries: CandleSeries[]) chartInstance.data.toXFromCandleIndex(idx: number) chartInstance.data.toXFromTimestamp timestamp: number number Converts timestamp to chart x coordinate chartInstance.data.toY price: number number Converts price to chart y coordinate chartInstance.data.updateAllSeries mainSeries: CandleSeries secondarySeries: CandleSeries[] void Updates the main and secondary series in one bulk operation. Reindexing and visual rerender happens at the same time. chartInstance.data.removeSecondarySeries(series: CandleSeriesModel) chartInstance.data.prependCandles(target: Candle[]) chartInstance.data.addLastCandle(candle: Candle) chartInstance.data.updateLastCandle(candle: Candle) chartInstance.data.updateCandles(candles: Candle[], instrumentSymbol: string) chartInstance.data.setOffsets(offsets: Partial<ChartConfigComponentsOffsets>) chartInstance.data.getDataSeriesDrawer(drawerType: keyof BarTypes) chartInstance.data.registerDataSeriesTypeDrawer(drawerType: string) chartInstance.data.updatePriceIncrementsIfNeeded(instrument: ChartInstrument) chartInstance.data.observeOffsetsChanged(Observable<void>) chartInstance.data.observeChartTypeChanged(Observable<keyof BarTypes>) chartInstance.data.observeCandlesChanged(Observable<void>) chartInstance.data.observeCandlesUpdated(Observable<void>)
// xAxis chartInstance.xAxis.doActivate() chartInstance.xAxis.getDrawer() chartInstance.xAxisregisterXAxisLabelsProvider(provider: XAxisLabelsProvider) chartInstance.xAxis.setVisible(boolean) chartInstance.xAxis.setFormatsForLabelsConfig(newFormatsByWeightMap: Record<TimeFormatWithDuration, string>) chartInstance.xAxis.isVisible()
// YAxisComponent chartInstance.yAxis.doActivate() chartInstance.yAxis.updateOrderedLabels(adjustYAxisWidth: boolean ) chartInstance.yAxis.registerDefaultLabelColorResolver() chartInstance.yAxis.registerYAxisLabelsProvider(provider: YAxisLabelsProvider, groupName: string) chartInstance.yAxis.setVisible(boolean) chartInstance.yAxis.isVisible() chartInstance.yAxis.addSimpleYAxisLabel(name: string,label: VisualYAxisLabel) chartInstance.yAxis.deleteSimpleYAxisLabel(name: string) chartInstance.yAxis.unregisterYAxisLabelsProvider(groupName: string) chartInstance.yAxis.registerYAxisWidthContributor(contributor: YAxisWidthContributor) chartInstance.yAxis.setAxisType(type: PriceAxisType) chartInstance.yAxis.setYAxisAlign(align: YAxisAlign) chartInstance.yAxis.setLockPriceToBarRatio(boolean) chartInstance.yAxis.changeLabelMode(type: string) chartInstance.yAxis.togglePriceScaleInverse(inverse: boolean) chartInstance.yAxis.changeLabelsDescriptionVisibility(descVisibility: boolean) chartInstance.yAxis.registerLabelColorResolver(chartType: keyof BarTypes, LabelColorResolver) chartInstance.yAxis.getLabelsColorResolver (candlesType: string)
// CrossToolComponent chartInstance.crosshair.setType(type: string) chartInstance.crosshair.registerDefaultDrawerTypes() chartInstance.crosshair.setVisible(boolean)
// EventsComponent chartInstance.events.setEvents(events: Event[]) chartInstance.events.setEventTypeVisible(eventsVisibility: Partial<Record<EventType, boolean>>) chartInstance.events.setVisible(boolean) chartInstance.events.observeEventHovered()
// VolumesComponent chartInstance.volumes.doDeactivate() chartInstance.volumes.setShowVolumesSeparatly(separate: boolean) chartInstance.volumes.setVisible(boolean) chartInstance.volumes.registerDefaultVolumeColorResolvers() chartInstance.volumes.registerVolumeColorResolver(chartType: keyof BarTypes, resolver: VolumeColorResolver)
// WaterMarkComponent chartInstance.watermark.setWaterMarkVisible(visible: boolean) chartInstance.watermark.setWaterMarkData(watermarkData) chartInstance.watermark.getWaterMarkData() chartInstance.watermark.setWaterMarkConfig(watermarkConfig) chartInstance.watermark.setLogoImage(img) chartInstance.watermark.recalculateTextSize(chartWidth: number, chartHeight: number)
// NavigationMapComponent chartInstance.navigationMap.setVisible(visible: boolean) chartInstance.navigationMap.makeVisualCandles() chartInstance.navigationMap.doActivate()
// SnapshotComponent chartInstance.snapshot.createSnapshot(userDrawCallback: (ctx: CanvasRenderingContext2D) => void) chartInstance.snapshot.doActivate()
// SnapshotComponent chartInstance.snapshot.setHighlights(highlights: Highlight[]) chartInstance.snapshot.getHighlights() chartInstance.snapshot.setHighlightsVisible(visible: boolean) chartInstance.snapshot.observeHighlightsUpdated()
// PaneManager chartInstance.PaneManager.addResizer(uuid: string) chartInstance.PaneManager.createPane(uuid: string, options: AtLeastOne<PaneCreationOptions>) chartInstance.PaneManager.createYAxisComponent(uuid: string, scaleModel: ScaleModel, formatter: (value: number) => string, subs: Unsubscriber[], increment: number) chartInstance.PaneManager.createYPanHandler(uuid: string, scaleModel: ScaleModel, subs: Unsubscriber[]) chartInstance.PaneManager.createGridComponent(uuid: string, ScaleModel, yAxisLabelsGenerator: NumericYAxisLabelsGenerator) chartInstance.PaneManager.addCursors(uuid: string) chartInstance.PaneManager.removeCursors(uuid: string) chartInstance.PaneManager.recalculateState()
// PaneComponent chartInstance.PaneComponent.doActivate() chartInstance.PaneComponent.updateView() chartInstance.PaneComponent.getBounds() chartInstance.PaneComponent.hide() chartInstance.PaneComponent.show() chartInstance.PaneComponent.getAxisType() chartInstance.PaneComponent.moveUp() chartInstance.PaneComponent.moveDown() chartInstance.PaneComponent.canMoveUp() chartInstance.PaneComponent.canMoveDown() chartInstance.PaneComponent.createDataSeries() chartInstance.PaneComponent.addDataSeries(series: DataSeriesModel<DataSeriesPoint, VisualSeriesPoint>) chartInstance.PaneComponent.removeDataSeries(series: DataSeriesModel<DataSeriesPoint, VisualSeriesPoint>) chartInstance.PaneComponent.setPaneValueFormatters(formatters: PaneFormatters) chartInstance.PaneComponent.regularValueFromY(y: number)
v2.7.6 (04/16/2025)
v2.5.8 (08/21/2024)
v2.5.7 (07/23/2024)
v2.5.6 (06/25/2024)
v2.5.5 (05/23/2024)
v2.5.4 (05/14/2024)
v2.5.3 (05/08/2024)
v2.5.2 (04/22/2024)
v2.5.1 (04/12/2024)
v2.5.0 (04/03/2024)
v2.4.6 (03/11/2024)
v2.4.5 (02/02/2024)
v2.4.4 (12/29/2023)
v2.4.3 (12/22/2023)
v2.4.1 (12/18/2023)
v2.0.0 (09/04/2023)
The post Intuitive Charting Library for Financial Data – DXCharts Lite appeared first on CSS Script.
It might be World War III, but at least I won $20. | Image: Polymarket…
President Donald Trump in a video posted by the White House on social media announces…
We’ve somehow already made our way to March, which hopefully brings some spring weather, but…
The pulse of Lumiose City is racing, and for good reason! Pre-orders for the Pokémon…
That’s coming on a little strong, maybe. | Image: Vera C. Rubin Observatory The Vera…
Threat actors are deploying a new phishing campaign that uses fake Zoom and Google Meet…
This website uses cookies.