Компоненты/Угольки

Угольки

28 сентября 2026

Шейдерный огонь: угли тлеют у нижнего края, пламя поднимается сквозь марево, искры взлетают и гаснут.

Установка

npx astra-rn add embers
pnpm dlx astra-rn add embers
yarn dlx astra-rn add embers
bunx --bun astra-rn add embers

Файлы

index.tsx
НазадДизерингДалееФеррожидкость

Медленный огонь во фрагментном шейдере: у нижнего края тлеют угли, пламя с цветом абсолютно чёрного тела поднимается сквозь дрожащее марево, а три слоя искр взлетают, мерцают и гаснут. Касание (или курсор в вебе) раздувает пламя и расталкивает искры вокруг пальца.

Шейдер считается на GPU через Skia, время и следование за пальцем идут на UI-потоке Reanimated. Анимация замирает при «Уменьшении движения», в фоне, при paused или (в вебе) вне экрана. Работает на iOS, Android и в вебе.

Вручную

Поставьте зависимости:

npm install @shopify/react-native-skia react-native-reanimated react-native-gesture-handler
pnpm add @shopify/react-native-skia react-native-reanimated react-native-gesture-handler
yarn add @shopify/react-native-skia react-native-reanimated react-native-gesture-handler
bun add @shopify/react-native-skia react-native-reanimated react-native-gesture-handler

Скопируйте эти файлы в src/shared/components/organisms/embers/:

Проверьте алиас путей. Импорты в коде выше записаны так, как их пишет astra-rn add: @/shared/components, @/shared/utils и @/shared/hooks. Нужен алиас "@/*": ["./src/*"] в tsconfig.json — или поправьте импорты под свои пути.

Использование

import React from "react";
import { StyleSheet, View } from "react-native";
import { Embers } from "@/shared/components/organisms/embers";
import { Showcase, useCustomize } from "~/showcase";

const SPARK = "#ffb852";
const GLOW = "#ff470a";
const BACKGROUND = "#030101";

const pick = (value: string, fallback: string): string | undefined =>
  value.toLowerCase() === fallback ? undefined : value;

const CUSTOMIZE = [
  { key: "heat", label: "Жар", type: "slider", min: 0, max: 1, step: 0.01, default: 0.6 },
  { key: "speed", label: "Скорость", type: "slider", min: 0, max: 3, step: 0.05, unit: "×", default: 1 },
  { key: "exposure", label: "Яркость", type: "slider", min: 0.3, max: 3, step: 0.05, default: 1.2 },
  { key: "sparkColor", label: "Цвет искр", type: "color", default: SPARK },
  { key: "glowColor", label: "Ореол искр", type: "color", default: GLOW },
  { key: "background", label: "Цвет фона", type: "color", default: BACKGROUND },
  { key: "interactive", label: "Реакция на курсор", type: "toggle", default: true },
] as const;

export default function EmbersScreen() {
  const custom = useCustomize(CUSTOMIZE);

  return (
    <Showcase>
      <View style={styles.container}>
        <Embers
          heat={custom.heat}
          speed={custom.speed}
          exposure={custom.exposure}
          interactive={custom.interactive}
          sparkColor={pick(custom.sparkColor, SPARK)}
          glowColor={pick(custom.glowColor, GLOW)}
          background={pick(custom.background, BACKGROUND)}
        />
      </View>
    </Showcase>
  );
}

const styles = StyleSheet.create({
  container: {
    ...StyleSheet.absoluteFillObject,
    backgroundColor: "#000000",
  },
});

Высота огня задаётся heat от 0 до 1, цвета принимают строку или тройку RGB от 0 до 1.

Пропсы

Пропс
Описание
speed?

Тип number

heat?

Тип number

interactive?

Тип boolean

sparkColor?

Тип ShaderColor

glowColor?

Тип ShaderColor

background?

Тип ShaderColor

exposure?

Тип number

paused?

Тип boolean

children?

Тип ReactNode

style?

Тип StyleProp<ViewStyle>