---
url: /templates/examples.md
description: >-
Готовые шаблоны и пользовательские команды — приветствие, кубик, магический
шар, экономика, топ с листанием, выбор роли, профиль, проверка по ЧС.
---
# Полезные примеры
Готовые шаблоны, которые можно скопировать и поменять под себя. У каждого примера написано, куда его вставить и какие настройки выбрать.
::: tip Как пользоваться
Наведите курсор на блок кода — справа появится кнопка копирования. UUID действий в примерах вымышленные: замените их на UUID своих действий из меню «⋯».
:::
## Приветствие с правилами { #welcome }
**Где:** «Приветствия» → «Приветствие при входе». Режим Rich, синтаксис Markdown.
```template
# Добро пожаловать, {{ member.name }}!
Ты **{{ chat.memberCount | number_format }}**-й участник **{{ chat.title }}**.
📜 Правила чата
1. Без рекламы и ссылок на другие чаты
2. Без оскорблений
3. Флуд и спам — мьют на час
{% do url_button('Полные правила', 'https://telegra.ph/pravila-chata') %}
```
# Добро пожаловать, Анна!
Ты **1 248**-й участник **Клуб Astral**.
📜 Правила чата
1. Без рекламы и ссылок на другие чаты
2. Без оскорблений
3. Флуд и спам — мьют на час
## Случайное число { #random }
**Где:** пользовательская команда `!ранд`, действие «Отправка сообщения».
```template
{% set minimum = arguments.get(1) %}
{% set maximum = arguments.get(2) %}
{% require minimum returning 'Пожалуйста, укажите минимальное значение!' %}
{% require minimum is number returning 'Минимальное значение должно быть числом!' %}
{% require maximum returning 'Пожалуйста, укажите максимальное значение!' %}
{% require maximum is number returning 'Максимальное значение должно быть числом!' %}
{% if (minimum > maximum) %}
{% return 'Максимальное значение должно быть больше минимального!' %}
{% endif %}
{{ member }}, вам выпало **{{ random(minimum, maximum) }}**
```
[Анна](#), вам выпало **42**
## Магический шар { #8ball }
**Где:** команда `!шар`, «Отправка сообщения». Ответы выпадают с разной вероятностью.
```template
{% require arguments.value returning 'Задай вопрос: !шар выиграем ли мы турнир?' %}
🎱 {{ random(
['Бесспорно', 'Скорее да', 'Спроси позже', 'Даже не думай', 'Звезды говорят — да'],
[25, 25, 20, 20, 10]
) }}
```
🎱 Звезды говорят — да
## Монетка с реакцией { #coin }
**Где:** команда `!монетка`, «Отправка сообщения».
```template
{% set side = random(['Орел', 'Решка']) %}
🪙 {{ member.name }} подбрасывает монетку… **{{ side }}**!
{% do reaction(side == 'Орел' ? '🔥' : '👍') %}
```
## Профиль участника { #profile }
**Где:** команда `!профиль`, «Отправка сообщения». Можно вызвать для себя или ответом на чужое сообщение.
```template
{% set m = arguments.targetMember ?: member %}
## {{ m.name }}
{{ table([
['Уровень', m.rank.level],
['Опыт', m.rank.totalExp | number_format],
['Место в чате', m.rank.rank],
['До следующего уровня', m.rank.remainingExp | number_format],
['Предупреждения', m.warnCount],
['В чате с', date(m.joinedAt, 'd MMMM yyyy')]
], { bordered: true, compact: true }) }}
```
## Анна Смирнова
| | |
|---|---|
| Уровень | 12 |
| Опыт | 18 430 |
| Место в чате | 7 |
| До следующего уровня | 880 |
| Предупреждения | 0 |
| В чате с | 11 апреля 2026 |
## Экономика: бонус, баланс, перевод { #economy }
Три команды, которые работают вместе. Монеты хранятся в [атрибуте](./storage/attributes) `coins` и дублируются в [индекс](./storage/indexes) `balances` для топа.
**`!бонус`** — раз в сутки +100 монет. «Отправка сообщения»:
```template
{% set last = member.getAttribute('bonus_at') %}
{% require now().millis - (last.value ?: 0) >= 86400000 returning '⏳ Бонус уже получен. Приходи завтра!' %}
{% set coins = member.getAttribute('coins').increment(100) %}
{% do last.update(now().millis) %}
{% do chat.getIndex('balances').get(member.id).update(coins) %}
💰 {{ member }}, +100 монет! Теперь у тебя **{{ coins | number_format }}** 🪙
```
**`!баланс`** — показать монеты. «Отправка сообщения», режим ответа — эфемерно:
```template
{% set m = arguments.targetMember ?: member %}
У {{ m.name }} **{{ (m.getAttribute('coins').value ?: 0) | number_format }}** 🪙
```
**`!перевод @кому сумма`** — «Отправка сообщения»:
```template
{% set target = arguments.targetMember %}
{% set amount = arguments.get(2) %}
{% require target returning 'Кому переводим? !перевод @anna 50' %}
{% require target.id != member.id returning 'Нельзя перевести самому себе' %}
{% require (amount is number) and amount > 0 returning 'Сумма должна быть положительным числом' %}
{% set mine = member.getAttribute('coins') %}
{% require (mine.value ?: 0) >= amount returning 'Недостаточно монет' %}
{% set left = mine.decrement(amount) %}
{% set theirs = target.getAttribute('coins').increment(amount) %}
{% set balances = chat.getIndex('balances') %}
{% do balances.get(member.id).update(left) %}
{% do balances.get(target.id).update(theirs) %}
💸 {{ member }} → {{ target }}: **{{ amount }}** 🪙
```
Команда пишет две записи индекса — это максимум за одно выполнение, см. [квоты](./advanced/limits#quotas).
## Топ с листанием { #top }
**Где:** команда `!топ`, «Отправка сообщения», флажок «Заменять сообщение с нажатой кнопкой» включен. Использует индекс `balances` из примера выше.
```template
{% set pageNum = (parameters.get('page')) ?: 0 %}
{% if component.id == 'next' and not (parameters.get('isLast')) %}{% set pageNum += 1 %}{% elseif component.id == 'prev' and pageNum > 0 %}{% set pageNum -= 1 %}{% endif %}
{% set page = chat.indexes.balances.getPageOf(pageNum, 10, 'DESC') %}
{% do parameters.store('page', page.number) %}
{% do parameters.store('isLast', page.isLast) %}
## 💰 Самые богатые · {{ page.number + 1 }}/{{ page.totalPages ?: 1 }}
{% for entry in page %}
{{ loop.index + page.number * page.size }}. {{ mention(entry.key) }} — {{ entry.value | number_format }} 🪙
{% else %}
Пока никто ничего не заработал.
{% endfor %}
{% do button('PRIMARY', 'prev', null, '⬅️', 'self', page.isFirst) %}
{% do button('PRIMARY', 'next', null, '➡️', 'self', page.isLast) %}
```
## 💰 Самые богатые · 1/4
1. [Анна](#) — 12 480 🪙
2. [Иван](#) — 9 150 🪙
3. [Олег](#) — 7 900 🪙
## Выбор роли из меню { #role-menu }
Участник выбирает роль бота — например, любимый режим игры.
**Действие 1 — «Меню»** (по умолчанию), «Отправка сообщения»:
```template
Выбери свой любимый режим — получишь роль и доступ к топику:
{% do select_menu('STRING', 'mode', 'Режим', 'a7c3e1f0-5b2d-4c8e-9f1a-2d3e4f5a6b7c')
.addOption('Броулбол', 'r_brawlball', '⚽')
.addOption('Захват кристаллов', 'r_gemgrab', '💎')
.addOption('Одиночное ШД', 'r_showdown', '🌵') %}
```
**Действие 2 — «Выдать»**, «Отправка сообщения», куда — эфемерно:
```template
{% set roleId = component.selectedOptions | first %}
{% transform r in ['r_brawlball', 'r_gemgrab', 'r_showdown'] as others %}
{% if r != roleId %}{% return r %}{% endif %}
{% endtransform %}
{% do member.modifyRoles([roleId], others) %}
Готово! Теперь у тебя роль {{ chat.getRole(roleId) }}.
```
`transform` собирает список «остальных» ролей, а `modifyRoles` одним вызовом выдает выбранную и снимает остальные. ID ролей (`r_brawlball` и другие) замените на ID своих ролей из раздела «Роли бота».
## Счетчик вызовов { #counter }
**Где:** любой шаблон. Считает, сколько раз его выполнили, в атрибуте чата.
```template
{% set n = bot.getAttribute('hello_count').increment(1) %}
Привет! Со мной поздоровались уже {{ n }} {{ plural(n, 'ru', 'раз', 'раза', 'раз', 'раза') }}.
```
## Проверка игрока по ЧС { #blacklist }
**Где:** команда `!чс`, «Отправка сообщения». Работает только в чате, привязанном к клубу Astral.
```template
{% set tag = arguments.get(1) | upper | replace('#', '') %}
{% require tag returning 'Укажи тег игрока: !чс ABCD1234' %}
{% set r = astral.blacklist.check(tag) %}
{% if r.blacklisted -%}
⛔ #{{ tag }} в черном списке ({{ r.type == 'project' ? 'проектный' : 'клубный' }}). Причина: {{ r.reason }}
{%- else -%}
✅ #{{ tag }} не найден в черном списке.
{%- endif %}
```
Больше примеров с данными Astral — в статье [Пространство astral](./astral#examples).
## Подтверждение бана кнопками { #ban-confirm }
Разобран подробно в статье [Кнопки и меню выбора](/commands/components#confirm).