diff --git a/websites/confetti/index.html b/websites/confetti/index.html index 7407681bce1..8b83d963133 100644 --- a/websites/confetti/index.html +++ b/websites/confetti/index.html @@ -156,9 +156,39 @@ target="_blank" rel="noopener noreferrer" > -
+ Blog + Cookie + Privacy +
+
+ + + + + + + + + + + + + + + + + + + + + + +

tsParticles Ribbons

@@ -352,6 +422,11 @@

Usage

by tsParticles + diff --git a/websites/ribbons/public/blog/customization-guide.html b/websites/ribbons/public/blog/customization-guide.html new file mode 100644 index 00000000000..edb84c0293c --- /dev/null +++ b/websites/ribbons/public/blog/customization-guide.html @@ -0,0 +1,203 @@ + + + + + + + + + Customizing Ribbon Animations | tsParticles Ribbons Blog + + + + + + +
+ ← Back to blog + +

Customizing Ribbon Animations

+

June 9, 2026 by Matteo Bruni

+ +

+ tsParticles Ribbons offers a wide range of customization options. You can change colors, + adjust physics, control positioning, and even create multi-layered effects by combining + multiple calls. +

+ +

Custom Colors

+

By default, ribbons use a preset palette, but you can provide your own color array:

+
ribbons({
+  colors: ['#FF4500', '#FF6347', '#FFD700', '#FF8C00', '#FF0000'],
+});
+

+ Colors can be any valid CSS color: hex codes, RGB, HSL, or named colors. You can create + themed effects like ocean blues, sunset oranges, or holiday reds and greens. To create a + smooth transition between two color themes, call ribbons() multiple times with + different color palettes and stagger them with setTimeout. +

+ +

Position Control

+

You can control where ribbons spawn by setting the positionX option:

+
ribbons({
+  positionX: 50, // spawn at x=50 (percentage-based)
+  emitterSize: { width: 0, height: 0 }, // point emitter
+});
+

+ The positionX value is a percentage (0-100) of the viewport width. Setting + emitterSize to zero creates a point emitter, making all ribbons originate from + a single pixel. This is great for effects that look like ribbons shooting from a specific + button or element. +

+ +

Physics and Timing

+

+ Ribbon animations are driven by tsParticles' physics engine. While the ribbons preset + provides sensible defaults, you can fine-tune the behavior through the underlying particle + configuration. The physics parameters that affect ribbons include gravity, velocity, + rotation, and decay rates. +

+

+ For continuous effects, you can use setInterval to spawn ribbons repeatedly: +

+
const duration = 8000;
+const animationEnd = Date.now() + duration;
+
+const interval = setInterval(function () {
+  const timeLeft = animationEnd - Date.now();
+  if (timeLeft <= 0) {
+    return clearInterval(interval);
+  }
+  ribbons();
+}, 260);
+

+ This creates a continuous fall effect for 8 seconds, with a new burst every 260 + milliseconds. Adjust the interval and duration to control density and length of the + animation. +

+ +

Multiple Bursts

+

+ You can layer multiple ribbon bursts with staggered timing for a rich, cascading effect: +

+
ribbons();
+
+setTimeout(() => {
+  ribbons();
+}, 300);
+
+setTimeout(() => {
+  ribbons();
+}, 600);
+

+ Each call creates an independent burst with its own set of ribbons. This technique is + perfect for celebrations, page load animations, or dramatic entrances. +

+ +

Custom Canvas

+

To keep ribbons within a specific area of your page, provide your own canvas element:

+
const canvas = document.getElementById('my-canvas');
+const shoot = await ribbons.create(canvas, {
+  zIndex: 0,
+});
+
+shoot();
+

+ This is useful when you want ribbons as a background for a specific section, or when you + need to avoid overlapping with interactive elements like forms or navigation menus. +

+ +

Combining Options

+

+ You can combine all these options to create unique effects. For example, a fireworks-style + ribbon burst from a fixed position with custom colors: +

+
ribbons({
+  positionX: 50,
+  emitterSize: { width: 0, height: 0 },
+  colors: ['#FFD700', '#FFA500', '#FF6347'],
+});
+

+ Experiment with different combinations on the interactive playground to find + the perfect effect for your project. +

+ +

Performance Considerations

+

+ Ribbon animations use the HTML5 Canvas API and are GPU-accelerated in modern browsers. For + the best performance: +

+ +

+ tsParticles is designed to be performant, with efficient particle pooling and minimal + garbage collection overhead. +

+
+ + + + + + diff --git a/websites/ribbons/public/blog/framework-integration.html b/websites/ribbons/public/blog/framework-integration.html new file mode 100644 index 00000000000..4b32063fa00 --- /dev/null +++ b/websites/ribbons/public/blog/framework-integration.html @@ -0,0 +1,239 @@ + + + + + + + + + Using Ribbons with React, Vue, and Angular | tsParticles Ribbons Blog + + + + + + +
+ ← Back to blog + +

Using Ribbons with React, Vue, and Angular

+

June 9, 2026 by Matteo Bruni

+ +

+ tsParticles Ribbons integrates seamlessly with modern JavaScript frameworks. The official + @tsparticles/react, @tsparticles/vue, and + @tsparticles/angular packages provide dedicated components that make + integration straightforward. +

+ +

React Integration

+

Install the required packages:

+
npm install @tsparticles/ribbons @tsparticles/react
+

Create a ribbons component:

+
import { useCallback } from 'react';
+import { Particles } from '@tsparticles/react';
+import { ribbons } from '@tsparticles/ribbons';
+
+export const RibbonsBackground = () => {
+  const particlesInit = useCallback(async (engine) => {
+    await ribbons.init(engine);
+  }, []);
+
+  const options = {
+    preset: 'ribbons',
+    background: {
+      color: '#000000',
+    },
+    fullScreen: {
+      enable: true,
+    },
+  };
+
+  return (
+    <Particles
+      id="ribbons"
+      init={particlesInit}
+      options={options}
+    />
+  );
+};
+

+ The Particles component handles canvas creation, resizing, and lifecycle + management automatically. Pass your ribbon configuration through the + options prop. +

+ +

Triggering Ribbons on Demand

+

+ For event-based ribbons (like button clicks), use the ribbons() function + directly: +

+
import { ribbons } from '@tsparticles/ribbons';
+
+function CelebrationButton() {
+  const handleClick = () => {
+    ribbons({
+      colors: ['#FFD700', '#FFA500'],
+      positionX: 50,
+      emitterSize: { width: 0, height: 0 },
+    });
+  };
+
+  return <button onClick={handleClick}>Celebrate!</button>;
+}
+ +

Vue.js Integration

+

Install the packages:

+
npm install @tsparticles/ribbons @tsparticles/vue3
+

Register the plugin and use the component:

+
import { createApp } from 'vue';
+import { ParticlesPlugin } from '@tsparticles/vue3';
+import { ribbons } from '@tsparticles/ribbons';
+
+const app = createApp(App);
+app.use(ParticlesPlugin, {
+  init: async (engine) => {
+    await ribbons.init(engine);
+  },
+});
+app.mount('#app');
+

Then in your component template:

+
<template>
+  <Particles
+    id="ribbons"
+    :options="{
+      preset: 'ribbons',
+      background: { color: '#000000' },
+      fullScreen: { enable: true },
+    }"
+  />
+</template>
+

For Vue 2.x, use @tsparticles/vue2 instead. The API is identical.

+ +

Angular Integration

+

Install the required packages:

+
npm install @tsparticles/ribbons @tsparticles/angular
+

Import the module and initialize ribbons:

+
import { NgParticlesModule } from '@tsparticles/angular';
+import { ribbons } from '@tsparticles/ribbons';
+
+@NgModule({
+  imports: [
+    NgParticlesModule.init({
+      init: async (engine) => {
+        await ribbons.init(engine);
+      },
+    }),
+  ],
+})
+export class AppModule { }
+

Use the component in your template:

+
<ng-particles
+  [id]="'ribbons'"
+  [options]="{
+    preset: 'ribbons',
+    background: { color: '#000000' },
+    fullScreen: { enable: true },
+  }"
+></ng-particles>
+ +

Svelte Integration

+

+ For Svelte applications, use the @tsparticles/ribbons package directly with + Svelte's onMount lifecycle: +

+
<script>
+  import { onMount } from 'svelte';
+  import { ribbons } from '@tsparticles/ribbons';
+
+  onMount(async () => {
+    await ribbons.init();
+    ribbons();
+  });
+</script>
+

Or use the svelte-particles package for a component-based approach.

+ +

Using with jQuery

+

If you're using jQuery, simply include the script tag and call ribbons():

+
<script src="https://cdn.jsdelivr.net/npm/@tsparticles/ribbons@latest/tsparticles.ribbons.bundle.min.js"></script>
+<script>
+  $(document).ready(function () {
+    ribbons();
+  });
+</script>
+

+ No additional plugin is needed — the ribbons function is available globally + after including the bundle. +

+ +

TypeScript Support

+

+ All tsParticles packages include TypeScript definitions. The ribbons() function + and the create() method are fully typed, providing autocomplete and type + checking in your IDE. +

+
import { ribbons, type RibbonsOptions } from '@tsparticles/ribbons';
+
+const options: RibbonsOptions = {
+  colors: ['#FF0000', '#00FF00', '#0000FF'],
+  positionX: 50,
+};
+
+ribbons(options);
+

Type definitions are included in the package and require no additional installation.

+
+ + + + + + diff --git a/websites/ribbons/public/blog/getting-started.html b/websites/ribbons/public/blog/getting-started.html new file mode 100644 index 00000000000..92a34dacbe4 --- /dev/null +++ b/websites/ribbons/public/blog/getting-started.html @@ -0,0 +1,161 @@ + + + + + + + + + Getting Started with tsParticles Ribbons | tsParticles Ribbons Blog + + + + + + +
+ ← Back to blog + +

Getting Started with tsParticles Ribbons

+

June 9, 2026 by Matteo Bruni

+ +

+ tsParticles Ribbons lets you add beautiful, flowing ribbon animations to your website with + minimal effort. Whether you want a subtle background effect or an eye-catching interactive + element, ribbons provide a elegant way to enhance your site's visual appeal. +

+ +

Quick Start with a Script Tag

+

+ The fastest way to add ribbons to any HTML page is with the CDN bundle. Add this script tag + to your page: +

+
<script src="https://cdn.jsdelivr.net/npm/@tsparticles/ribbons@latest/tsparticles.ribbons.bundle.min.js"></script>
+

Then call the ribbons() function anywhere in your JavaScript:

+
ribbons();
+

+ That's it. By default, ribbons will fall from random positions across the top of the page + with vibrant colors and smooth physics. +

+ +

Installation via npm

+

+ If you're using a build tool like Vite, webpack, or Rollup, install the package from npm: +

+
npm install @tsparticles/ribbons
+

Then import and call it in your JavaScript:

+
import { ribbons } from '@tsparticles/ribbons';
+
+await ribbons.init();
+ribbons();
+

+ The init() method is required once before creating any ribbon animations. It + loads the necessary engine and plugins. +

+ +

Using the create Method

+

+ For more control, use the ribbons.create() method. This returns a function + bound to a specific canvas element, letting you control exactly where ribbons appear: +

+
import { ribbons } from '@tsparticles/ribbons';
+
+await ribbons.init();
+
+const canvas = document.getElementById('my-canvas');
+const shoot = await ribbons.create(canvas, {
+  zIndex: 0,
+});
+
+// Fire a burst of ribbons
+shoot();
+ +

Creating from Scratch with npm create

+

You can scaffold a complete project with the official template:

+
npm create ribbons@latest
+

+ This will create a new directory with a pre-configured project that includes the ribbons + package, a sample HTML file, and a build setup. +

+ +

What Happens When You Call ribbons()

+

+ When you invoke the ribbons() function, it creates a burst of ribbon-like + particles that animate across the screen. Each ribbon is a curved strip that follows a + physics simulation, creating a natural, organic feel. The ribbons are rendered on a + full-screen canvas overlay by default, giving the impression of floating or falling ribbons + on top of your page content. +

+

+ The default configuration spawns ribbons from a random position along the top edge of the + viewport. Each ribbon has a random color from a preset palette, a random velocity, and a + natural gravity effect that pulls it downward while it drifts and rotates. +

+ +

Next Steps

+

+ Once you have ribbons running, explore the + customization guide to learn how to change + colors, physics, and positioning. For framework-specific integration, check the + framework integration guide. +

+

+ You can also experiment with all the options interactively on the + playground page, where each mode comes with a live code editor. +

+
+ + + + + + diff --git a/websites/ribbons/public/blog/index.html b/websites/ribbons/public/blog/index.html new file mode 100644 index 00000000000..8edb3f459fc --- /dev/null +++ b/websites/ribbons/public/blog/index.html @@ -0,0 +1,105 @@ + + + + + + + + + Blog | tsParticles Ribbons + + + + + + +
+

tsParticles Ribbons Blog

+

Tutorials, guides, and news about creating ribbon animations with tsParticles.

+ + +
+ + + + + + diff --git a/websites/ribbons/public/cookie-policy.html b/websites/ribbons/public/cookie-policy.html index e86a1499001..a062ec42da0 100644 --- a/websites/ribbons/public/cookie-policy.html +++ b/websites/ribbons/public/cookie-policy.html @@ -5,49 +5,201 @@ Cookie Policy | tsParticles Ribbons - + -
+ + +

Cookie Policy

+

Last updated: June 9, 2026

+

- This website uses optional cookies to improve content quality and to support the project - with ads. + This website uses optional cookies and local storage to improve content quality and to + support the project with ads. This policy explains what cookies we use, why we use them, and + how you can control them.

-

Categories

+

What Are Cookies

- Analytics: used to understand aggregate usage of the website through Google - Analytics. + Cookies are small text files stored on your device by your web browser. They are widely used + to make websites work more efficiently and to provide information to site owners. Local + storage is similar but stores data directly in your browser without sending it to the server + on every request.

-

Advertising: used to show ads through Google AdSense.

-

Consent and control

+

Categories of Cookies We Use

+ +

Essential Storage

- Analytics cookies and personalized advertising are enabled only after explicit consent. You - can reject all, accept all, or save a custom choice from the privacy banner. + We use browser localStorage (not cookies) to store your cookie consent preferences under the + key tsparticles-ribbons/cookie-consent-v1. This preference is stored locally + and is not sent to any server. No essential cookies are used by this website. +

+ +

Analytics Cookies (Optional)

+

Provider: Google Analytics (Measurement ID: G-CQTMTXX07T)

+

+ Purpose: Used to understand aggregate usage of the website. We collect anonymized + data about which pages are visited, how long visitors stay, and what browser or device they + use. This helps us improve the website's content and user experience. +

+

+ Data collected: Anonymized IP address, page URLs, browser type, device type, + approximate country-level location, referral source. No personally identifiable information + is collected or stored. +

+

Retention: Analytics data is retained for 26 months.

+

+ Analytics cookies are loaded only after you give explicit consent. If you reject analytics + cookies, the website still uses Google Consent Mode to send a signal that analytics consent + was denied, enabling cookieless measurement without storing any cookies. +

+ +

Advertising Cookies (Optional)

+

Provider: Google AdSense (Publisher ID: pub-1784552607103901)

+

+ Purpose: Used to show relevant advertisements on the website. AdSense helps support + the ongoing development and maintenance of the tsParticles open-source project. +

+

+ Data collected: When you consent to advertising, Google AdSense may use cookies to + show personalized ads based on your browsing interests. Data collected may include browser + information, device type, and anonymous browsing patterns.

- If analytics cookies are rejected, the website can still use anonymous cookieless analytics - measurement (Google Consent Mode) without storing analytics cookies. + Advertising cookies are loaded only after you give explicit consent. If you reject + advertising cookies, AdSense still loads but operates in non-personalized mode, showing ads + based on the page content rather than your browsing history. Google Consent Mode signals + (ad_storage, ad_user_data, ad_personalization) are + set to denied when consent is not given.

+ +

Third-Party Cookies

- You can change your choice at any time from the Cookie preferences button in the - website footer. + This website does not set any third-party cookies directly. However, Google Analytics and + Google AdSense may set their own cookies as described above. These services are governed by + their own privacy policies:

+ -

Storage

+

Consent and Control

+

+ Analytics cookies and personalized advertising are enabled only after explicit consent. You + can manage your preferences in the following ways: +

+

Your preference is stored locally in your browser using localStorage under a consent key - dedicated to this website. + dedicated to this website. Clearing your browser data will reset these preferences. +

+ +

Google Consent Mode v2

+

+ This website implements Google Consent Mode v2, which communicates your consent choices to + Google services through the following signals: +

+ +

+ Additional privacy protections include ads_data_redaction (URL-level ad data is + redacted when consent is denied) and url_passthrough (improved conversion + measurement without cookies). +

+ +

Contact

+

+ If you have questions about this cookie policy, please open an issue on the + tsParticles GitHub repository.

Back to the homepage

+ + + + diff --git a/websites/ribbons/public/css/index.css b/websites/ribbons/public/css/index.css index 7044e0b84c6..dcba62e7c6d 100644 --- a/websites/ribbons/public/css/index.css +++ b/websites/ribbons/public/css/index.css @@ -26,6 +26,17 @@ --theme-switch: var(--switch-sun-black); } +@media (prefers-color-scheme: light) { + :root { + --primary-color: #212121; + --secondary-color: #ffffff; + --background-color: #f0f0f0; + --inner-color: #363636; + + --theme-switch: var(--switch-sun-black); + } +} + [auto-theme] { --theme-switch: var(--switch-auto-white); } @@ -110,6 +121,33 @@ header { fill: var(--primary-color); } +.header-sep { + display: block; + width: 1px; + height: 20px; + background: var(--border-color); + margin-right: 12px; +} + +.header-link { + color: var(--primary-color); + text-decoration: none; + font-size: 0.8rem; + margin-right: 8px; + padding: 0.3rem 0.55rem; + border: 1px solid var(--border-color); + border-radius: 6px; + transition: + background 120ms ease, + border-color 120ms ease; + line-height: 1; +} + +.header-link:hover { + background: rgba(255, 255, 255, 0.1); + border-color: var(--primary-color); +} + h1, h2, .center { @@ -418,13 +456,15 @@ footer a:hover { .cookie-policy-link { display: inline-block; - margin: 0 0 1rem; color: var(--inner-color); - opacity: 0.85; + text-decoration: none; + padding: 0.3rem 0.6rem; + border-radius: 6px; + transition: background 120ms ease; } .cookie-policy-link:hover { - opacity: 1; + background: rgba(255, 255, 255, 0.1); } .cookie-consent-banner { @@ -495,6 +535,13 @@ footer a:hover { .policy-container a { color: var(--primary-color); + text-decoration: none; + border-bottom: 1px solid rgba(255, 255, 255, 0.2); + transition: border-color 120ms ease; +} + +.policy-container a:hover { + border-bottom-color: var(--primary-color); } .custom-canvas { @@ -523,6 +570,239 @@ footer a:hover { } } +.site-nav { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 100; + display: flex; + align-items: center; + height: 48px; + padding: 0 0.5rem; + background: var(--secondary-color); + border-bottom: 1px solid var(--border-color); +} + +.site-nav-links { + display: flex; + gap: 0.25rem; + align-items: center; + margin: 0 auto; +} + +.site-nav a { + color: var(--primary-color); + text-decoration: none; + font-size: 0.85rem; + padding: 0.35rem 0.7rem; + border-radius: 6px; + transition: background 120ms ease; +} + +.site-nav a:hover { + background: rgba(255, 255, 255, 0.1); +} + +.site-nav .site-nav-current { + font-weight: 700; + background: rgba(255, 255, 255, 0.08); +} + +.site-nav-theme { + --size: 22px; + position: relative; + display: block; + width: var(--size); + height: var(--size); + background: none; + border: none; + outline: none; + margin-left: auto; + cursor: pointer; +} + +.site-nav-theme:after { + position: absolute; + top: 0; + left: 0; + content: ''; + width: var(--size); + height: var(--size); + background-repeat: no-repeat; + background-position: center; + background: var(--theme-switch); +} + +.site-nav-theme:hover { + background: rgba(255, 255, 255, 0.1); + border-color: var(--primary-color); +} + +.content-page { + max-width: 800px; + margin: 0 auto; + padding: 5rem 1rem 3rem; + line-height: 1.8; +} + +.content-page h1 { + margin-top: 2rem; + margin-bottom: 1rem; + text-align: left; +} + +.content-page h2 { + margin-top: 2.5rem; + margin-bottom: 0.75rem; + text-align: left; +} + +.content-page h3 { + margin-top: 1.5rem; + margin-bottom: 0.5rem; +} + +.content-page p { + margin: 1em 0; +} + +.content-page ul, +.content-page ol { + margin: 1em 0; + padding-left: 2em; +} + +.content-page li { + margin: 0.4em 0; +} + +.content-page code { + background: var(--secondary-variant-color); + padding: 0.15em 0.4em; + border-radius: 4px; + font-size: 0.9em; +} + +.content-page pre { + background: var(--secondary-variant-color); + padding: 1rem; + border-radius: 8px; + overflow-x: auto; + line-height: 1.4; +} + +.content-page pre code { + background: none; + padding: 0; +} + +.content-page a { + color: var(--inner-color); + text-decoration: none; + border-bottom: 1px solid rgba(255, 255, 255, 0.2); + transition: + border-color 120ms ease, + opacity 120ms ease; +} + +.content-page a:hover { + border-bottom-color: var(--inner-color); +} + +.content-page a code { + border-bottom: none; +} + +.content-page img { + max-width: 100%; + border-radius: 8px; +} + +.content-page blockquote { + border-left: 4px solid var(--border-color); + margin: 1em 0; + padding: 0.5em 1em; + background: var(--secondary-variant-color); + border-radius: 0 8px 8px 0; +} + +.content-page hr { + border: none; + border-top: 1px solid var(--border-color); + margin: 2rem 0; +} + +.content-page .meta { + font-size: 0.85rem; + opacity: 0.7; + margin-bottom: 2rem; +} + +.content-page .back-link { + display: inline-block; + margin-bottom: 1rem; + font-size: 0.85rem; + opacity: 0.7; + text-decoration: none; + border-bottom: none; +} + +.content-page .back-link:hover { + opacity: 1; +} + +.blog-list { + list-style: none; + padding: 0; +} + +.blog-list li { + margin: 2rem 0; + padding-bottom: 2rem; + border-bottom: 1px solid var(--border-color); +} + +.blog-list h2 { + margin: 0 0 0.25rem; +} + +.blog-list .blog-excerpt { + margin: 0.5rem 0; + opacity: 0.85; +} + +.blog-list .blog-meta { + font-size: 0.8rem; + opacity: 0.6; +} + +.blog-list a { + color: var(--primary-color); + text-decoration: none; +} + +.blog-list a:hover { + text-decoration: underline; +} + +.footer-links { + display: flex; + justify-content: center; + flex-wrap: wrap; + margin-top: 0.5rem; +} + +.footer-links .cookie-policy-link + .cookie-policy-link { + margin-left: 0.5rem; +} + +.footer-links .cookie-policy-link + .cookie-policy-link::before { + content: '·'; + margin-right: 0.5rem; + opacity: 0.4; +} + .dh-banner { margin-top: 64px !important; } diff --git a/websites/ribbons/public/llms.txt b/websites/ribbons/public/llms.txt index 88b7c38ab2f..23a636b95fe 100644 --- a/websites/ribbons/public/llms.txt +++ b/websites/ribbons/public/llms.txt @@ -5,6 +5,9 @@ ## Docs - [Ribbons Modes](https://ribbons.js.org/): Interactive ribbon animation demos with live code editor +- [Getting Started Guide](https://ribbons.js.org/blog/getting-started.html): Quick start with script tags, npm, and framework components +- [Customization Guide](https://ribbons.js.org/blog/customization-guide.html): Colors, physics, positioning, and timing options +- [Framework Integration](https://ribbons.js.org/blog/framework-integration.html): Using ribbons with React, Vue, Angular, and Svelte - [tsParticles Documentation](https://particles.js.org/): Main tsParticles documentation site - [tsParticles GitHub](https://github.com/tsparticles/tsparticles): Source code and issue tracker diff --git a/websites/ribbons/public/privacy-policy.html b/websites/ribbons/public/privacy-policy.html new file mode 100644 index 00000000000..583c4eebe63 --- /dev/null +++ b/websites/ribbons/public/privacy-policy.html @@ -0,0 +1,211 @@ + + + + + + + + + Privacy Policy | tsParticles Ribbons + + + + + + +
+

Privacy Policy

+

Last updated: June 9, 2026

+ +

+ This privacy policy explains how ribbons.js.org (the "Site") collects, uses, and protects + information about visitors. The Site is operated by Matteo Bruni as an open-source project + under the tsParticles organization. +

+ +

Information We Collect

+ +

Analytics Data

+

+ When you consent to analytics cookies, we use Google Analytics to collect anonymized usage + data, including: +

+ +

+ This data is anonymized (IP addresses are anonymized before recording) and used solely to + improve the Site's content and user experience. We do not track individual visitors across + different websites. +

+ +

Advertising Data

+

When you consent to advertising cookies, Google AdSense may collect:

+ +

+ If advertising consent is declined, Google AdSense is still loaded but operates in + non-personalized mode, showing ads based on page content rather than user behavior. +

+ +

Information We Do NOT Collect

+

We do not collect or store:

+ + +

How We Use Your Data

+

We use collected data for the following purposes:

+ +

+ We do not sell your data to third parties. We do not use data for automated decision-making + or profiling beyond what is described above. +

+ +

Cookies and Local Storage

+

This Site uses both cookies and browser local storage:

+ +

For full details, see the Cookie Policy.

+ +

Third-Party Services

+

This Site uses the following third-party services:

+ +

+ Each service operates under its own privacy policy. We encourage you to review their + policies for complete information. +

+ +

Data Retention

+

+ Analytics data is retained for 26 months, after which it is automatically deleted. No + individual user data is stored on our servers — all data is processed by Google Analytics + and Google AdSense under their respective retention policies. +

+ +

Your Rights

+

Depending on your location, you may have the following rights regarding your data:

+ +

+ To exercise these rights, please open an issue on the + tsParticles GitHub repository. +

+ +

Changes to This Policy

+

+ We may update this privacy policy from time to time. Changes will be posted on this page + with an updated revision date. Significant changes will be announced on the tsParticles + GitHub repository. +

+ +

Back to the homepage

+
+ + + + + + diff --git a/websites/ribbons/public/sitemap.xml b/websites/ribbons/public/sitemap.xml index 40f572b954a..bfc90908e47 100644 --- a/websites/ribbons/public/sitemap.xml +++ b/websites/ribbons/public/sitemap.xml @@ -2,13 +2,43 @@ https://ribbons.js.org/ - 2026-06-04 + 2026-06-09 monthly 1 + + https://ribbons.js.org/blog/ + 2026-06-09 + monthly + 0.8 + + + https://ribbons.js.org/blog/getting-started.html + 2026-06-09 + monthly + 0.7 + + + https://ribbons.js.org/blog/customization-guide.html + 2026-06-09 + monthly + 0.7 + + + https://ribbons.js.org/blog/framework-integration.html + 2026-06-09 + monthly + 0.7 + https://ribbons.js.org/cookie-policy.html - 2026-06-04 + 2026-06-09 + monthly + 0.3 + + + https://ribbons.js.org/privacy-policy.html + 2026-06-09 monthly 0.3 diff --git a/websites/ribbons/src/style.css b/websites/ribbons/src/style.css index 332fbe6d4af..c9d5a393818 100644 --- a/websites/ribbons/src/style.css +++ b/websites/ribbons/src/style.css @@ -63,10 +63,10 @@ header { top: 0; left: 0; display: flex; - justify-content: flex-end; align-items: center; width: 100%; height: 64px; + padding: 0 12px; } .theme { @@ -523,3 +523,50 @@ footer a:hover { .dh-banner { margin-top: 64px !important; } + +.header-left { + display: flex; + align-items: center; + gap: 0.25rem; + margin-right: auto; +} + +.header-link { + color: var(--primary-color); + text-decoration: none; + font-size: 0.8rem; + padding: 0.3rem 0.55rem; + border: 1px solid var(--border-color); + border-radius: 6px; + transition: + background 120ms ease, + border-color 120ms ease; + line-height: 1; +} + +.header-link:hover { + background: rgba(255, 255, 255, 0.1); + border-color: var(--primary-color); +} + +.header-right { + display: flex; + align-items: center; +} + +.footer-links { + display: flex; + justify-content: center; + flex-wrap: wrap; + margin-top: 0.5rem; +} + +.footer-links .cookie-policy-link + .cookie-policy-link { + margin-left: 0.5rem; +} + +.footer-links .cookie-policy-link + .cookie-policy-link::before { + content: '·'; + margin-right: 0.5rem; + opacity: 0.4; +} diff --git a/websites/website/package.json b/websites/website/package.json index 0f351bd58bd..e2c10178f21 100644 --- a/websites/website/package.json +++ b/websites/website/package.json @@ -276,7 +276,7 @@ ], "targets": { "build": { - "cache": true, + "cache": false, "outputs": [ "{projectRoot}/docs/.vitepress/dist", "{projectRoot}/docs/.vitepress/cache"