feat: season 2 'Summer Tide' content and manifest generator

Adds Summer Tide (season_002) — 30 stages with deep-teal gradient and
cyan accent — generated remote-only (no copyToAssets). Introduces
tool/make_manifest.dart to rebuild content/manifest.json from all
season packs with SHA-256 verification support.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 13:45:22 +09:00
parent 9763968db9
commit ba70db3e60
5 changed files with 2346 additions and 0 deletions
+19
View File
@@ -0,0 +1,19 @@
{
"schemaVersion": 1,
"minAppBuild": 1,
"current": "season_002",
"seasons": [
{
"seasonId": "season_001",
"version": 1,
"packUrl": "seasons/season_001/pack.json",
"sha256": "5b20b88251931838563aaaa7729f48e5a35f09dbf80c576b9bc2ec944050fc0a"
},
{
"seasonId": "season_002",
"version": 1,
"packUrl": "seasons/season_002/pack.json",
"sha256": "47cc115f9982ade7df686b28aa95a82edcc1e8a4aae5f13319e7131477855de3"
}
]
}
File diff suppressed because it is too large Load Diff
+36
View File
@@ -0,0 +1,36 @@
# season_002 difficulty report
30 stages, 80 bot runs each, generated in 4s.
| stage | objective | moves | bot win rate | 2★/3★ movesLeft |
|---|---|---|---|---|
| season_002_001 | clearGems 1 | 7 | 83% | 3/4 |
| season_002_002 | clearGems 1 | 8 | 79% | 4/5 |
| season_002_003 | clearGems 2 | 11 | 91% | 4/5 |
| season_002_004 | clearGems 2 | 12 | 86% | 5/6 |
| season_002_005 | reachScore 990 | 25 | 100% | 6/9 |
| season_002_006 | clearGems 3 | 24 | 74% | 11/17 |
| season_002_007 | clearLines 5 | 23 | 100% | 6/8 |
| season_002_008 | clearGems 2 | 6 | 75% | 2/3 |
| season_002_009 | clearGems 4 | 14 | 86% | 6/7 |
| season_002_010 | reachScore 1476 | 31 | 100% | 9/11 |
| season_002_011 | clearGems 4 | 16 | 95% | 6/9 |
| season_002_012 | clearGems 4 | 15 | 70% | 5/7 |
| season_002_013 | clearGems 4 | 20 | 75% | 9/11 |
| season_002_014 | clearLines 7 | 27 | 99% | 5/7 |
| season_002_015 | reachScore 1766 | 30 | 96% | 4/8 |
| season_002_016 | clearGems 5 | 10 | 73% | 3/5 |
| season_002_017 | clearGems 5 | 21 | 65% | 7/10 |
| season_002_018 | clearGems 6 | 27 | 74% | 9/13 |
| season_002_019 | clearGems 6 | 20 | 73% | 4/7 |
| season_002_020 | reachScore 2185 | 33 | 93% | 5/8 |
| season_002_021 | clearLines 8 | 23 | 79% | 1/3 |
| season_002_022 | clearGems 5 | 28 | 85% | 6/12 |
| season_002_023 | clearGems 7 | 26 | 76% | 6/10 |
| season_002_024 | clearGems 7 | 21 | 83% | 5/10 |
| season_002_025 | reachScore 2692 | 39 | 93% | 7/11 |
| season_002_026 | clearGems 6 | 31 | 59% | 9/15 |
| season_002_027 | clearGems 6 | 13 | 65% | 2/5 |
| season_002_028 | clearLines 10 | 27 | 89% | 2/4 |
| season_002_029 | clearGems 7 | 27 | 69% | 8/10 |
| season_002_030 | reachScore 3006 | 37 | 80% | 2/6 |
+15
View File
@@ -0,0 +1,15 @@
{
"seasonId": "season_002",
"version": 1,
"title": { "en": "Summer Tide", "ko": "여름 파도" },
"theme": {
"tileSet": "summer",
"background": "",
"backgroundGradient": [4278854704, 4279253322, 4280179302],
"accentColor": 4285517301,
"particleType": "petals"
},
"stageCount": 30,
"baseSeed": 20260612,
"runsPerStage": 80
}
+41
View File
@@ -0,0 +1,41 @@
import 'dart:convert';
import 'dart:io';
import 'package:crypto/crypto.dart';
/// Builds content/manifest.json from the season packs under content/.
/// Usage: dart run tool/make_manifest.dart
void main() {
final contentDir = Directory('content');
final seasons = <Map<String, dynamic>>[];
final dirs = contentDir
.listSync()
.whereType<Directory>()
.where((d) => File('${d.path}/pack.json').existsSync())
.toList()
..sort((a, b) => a.path.compareTo(b.path));
for (final dir in dirs) {
final file = File('${dir.path}/pack.json');
final bytes = file.readAsBytesSync();
final pack = jsonDecode(utf8.decode(bytes)) as Map<String, dynamic>;
seasons.add({
'seasonId': pack['seasonId'],
'version': pack['version'],
'packUrl': 'seasons/${pack['seasonId']}/pack.json',
'sha256': sha256.convert(bytes).toString(),
});
}
final manifest = {
'schemaVersion': 1,
'minAppBuild': 1,
'current': seasons.isEmpty ? '' : seasons.last['seasonId'],
'seasons': seasons,
};
File('content/manifest.json').writeAsStringSync(
'${const JsonEncoder.withIndent(" ").convert(manifest)}\n');
stdout.writeln('manifest.json written with ${seasons.length} season(s).');
}