🌙 Уютная викторина — Calm Family Quiz
Спокойная семейная игра-викторина в стиле «Своей игры», созданная для уютного вечера перед сном. Все смотрят на одно табло, ведущий управляет игрой, команда отвечает вместе — без таймеров, давления и спешки.
🚀 Запуск
npm install
npm run dev
Откройте адрес из консоли (обычно http://localhost:5173).
Прочее
npm run build # production-сборка
npm run preview # предпросмотр сборки
npm run check # проверка типов (svelte-check)
🎮 Как играть
- Выбор набора — выберите тему вопросов.
- Табло — категории и карточки очков (100 / 200 / 300 / 500 / 1000). Чем дороже карточка, тем сложнее вопрос.
- Ведущий открывает вопрос, затем «Показать ответ», и решает:
- Засчитать +N — команде идут очки;
- Засчитать частично +N/2 — для «почти правильного» ответа ведущий может дать половину стоимости вопроса;
- Не засчитывать — без очков, но вопрос закрыт.
- Штрафов и минусов нет.
- У некоторых вопросов есть необязательная подсказка 💡. Ведущий может показать её по желанию. Если подсказка показана — ответ засчитывается только за половину стоимости: мягкая помощь без давления.
- Для творческих вопросов (type
creative) кнопка мягче: «Засчитать творческий ответ +N». - Сыгранный вопрос затемняется и больше не выбирается.
- Когда сыграны все вопросы — экран результата с мягкой финальной фразой.
Прогресс сохраняется автоматически — после перезагрузки игра продолжится с того же места.
🧩 Добавление нового набора вопросов
Архитектура задумана так, чтобы наборы добавлялись без правок UI.
Структура набора: ровно 5 категорий, в каждой ровно 5 вопросов с
номиналами 100 / 200 / 300 / 500 / 1000 (от простого к сложному). Вопросы
бывают strict (однозначный ответ) и creative (творческий). У вопроса может
быть необязательное поле optionalHint — подсказка для ведущего.
-
Создайте файл
src/lib/question-sets/<name>.ts:import type { QuestionSet } from '$lib/types'; export const mySet: QuestionSet = { id: 'my-set', // уникальный title: 'Моя тема', description: 'Короткое описание', ageRange: '6+ лет', categories: [ { id: 'cat-1', // уникально в пределах набора title: 'Категория', questions: [ { id: 'q1', points: 100, question: '...', answer: '...', type: 'strict' }, { id: 'q2', points: 200, question: '...', answer: '...', optionalHint: '...', type: 'strict' }, { id: 'q3', points: 300, question: '...', answer: '...', type: 'strict' }, { id: 'q4', points: 500, question: '...', answer: '...', type: 'creative' }, { id: 'q5', points: 1000, question: '...', answer: '...', type: 'strict' } // ровно 5 вопросов с очками 100/200/300/500/1000 ] } // …ещё 4 категории (всего 5) ] }; -
Зарегистрируйте набор в
src/lib/question-sets/index.ts:import { mySet } from './my-set'; export const questionSets = [animalsSet, cozySet, mySet];
Готово — набор автоматически появится на экране выбора.
🏗️ Архитектура
Код аккуратно разделён по слоям:
src/
├─ lib/
│ ├─ types.ts # Доменные типы (Question, Category, QuestionSet, GameState)
│ ├─ question-sets/ # ДАННЫЕ (отделены от UI)
│ │ ├─ animals.ts # набор-заглушка
│ │ ├─ cozy.ts # набор-заглушка
│ │ └─ index.ts # реестр наборов + хелперы поиска
│ ├─ stores/
│ │ └─ game.ts # СОСТОЯНИЕ игры (Svelte store + localStorage)
│ └─ components/ # UI-компоненты
│ ├─ QuestionSetSelector.svelte
│ ├─ GameBoard.svelte
│ ├─ QuestionCard.svelte
│ ├─ ScorePanel.svelte
│ ├─ QuestionModal.svelte
│ ├─ HostControls.svelte
│ ├─ GameResult.svelte
│ └─ ConfirmDialog.svelte
└─ routes/
├─ +layout.svelte # подключение глобальных стилей
├─ +layout.ts # CSR-only (localStorage)
└─ +page.svelte # оркестрация экранов
Принципы:
- Данные вопросов полностью отделены от состояния и UI.
- Состояние игры живёт в Svelte store с автосохранением в
localStorageи восстанавливается после перезагрузки. - Очки берутся из данных вопроса — ничего не хардкодится в UI.
- Никакого бэкенда, БД, авторизации, мультиплеера или редактора в MVP.
🎨 Стек
- SvelteKit + TypeScript
- Tailwind CSS v4 (через
@tailwindcss/vite) - Без тяжёлых UI-библиотек — только лёгкие зависимости.
Лицензия: личный/семейный проект.