453 lines
23 KiB
PHP
453 lines
23 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Database\Seeders;
|
|
|
|
use App\Models\AcademyBadge;
|
|
use App\Models\AcademyCategory;
|
|
use App\Models\AcademyChallenge;
|
|
use App\Models\AcademyLesson;
|
|
use App\Models\AcademyLessonBlock;
|
|
use App\Models\AcademyPromptPack;
|
|
use App\Models\AcademyPromptPackItem;
|
|
use App\Models\AcademyPromptTemplate;
|
|
use App\Services\Academy\AcademyCacheService;
|
|
use Illuminate\Database\Seeder;
|
|
|
|
class AcademyDemoSeeder extends Seeder
|
|
{
|
|
public function run(): void
|
|
{
|
|
$this->call(AcademyCategorySeeder::class);
|
|
|
|
$categories = AcademyCategory::query()->get()->keyBy('slug');
|
|
|
|
$lessons = [
|
|
[
|
|
'slug' => 'what-is-ai-assisted-digital-art',
|
|
'category_slug' => 'prompting-basics',
|
|
'title' => 'What Is AI-Assisted Digital Art?',
|
|
'excerpt' => 'A grounded overview of how Skinbase creators can use AI as a creative assistant instead of a shortcut.',
|
|
'content' => 'AI-assisted digital art combines prompt-driven ideation, composition decisions, and manual finishing into a single workflow that still depends on taste and intent.',
|
|
'difficulty' => 'beginner',
|
|
'access_level' => 'free',
|
|
'lesson_type' => 'article',
|
|
'featured' => true,
|
|
],
|
|
[
|
|
'slug' => 'prompting-basics-for-skinbase-creators',
|
|
'category_slug' => 'prompting-basics',
|
|
'title' => 'Prompting Basics for Skinbase Creators',
|
|
'excerpt' => 'Learn how to describe subject, mood, lighting, composition, and finish for Skinbase-native prompt workflows.',
|
|
'content' => 'Start with a clear subject. Add mood and lighting. Then anchor the composition for the output you actually want to upload.',
|
|
'difficulty' => 'beginner',
|
|
'access_level' => 'free',
|
|
'lesson_type' => 'article',
|
|
'featured' => true,
|
|
],
|
|
[
|
|
'slug' => 'ai-ethics-and-skinbase-upload-rules',
|
|
'category_slug' => 'ai-ethics',
|
|
'title' => 'AI Ethics and Skinbase Upload Rules',
|
|
'excerpt' => 'Use AI responsibly, label your workflow clearly, and avoid imitation-based prompt packs.',
|
|
'content' => 'Respect artists, disclose your workflow, and avoid packaging prompts around living-artist imitation or deceptive attribution.',
|
|
'difficulty' => 'beginner',
|
|
'access_level' => 'free',
|
|
'lesson_type' => 'ethics',
|
|
'featured' => false,
|
|
],
|
|
[
|
|
'slug' => 'how-to-prepare-ai-artwork-for-upload',
|
|
'category_slug' => 'wallpapers',
|
|
'title' => 'How to Prepare AI Artwork for Upload',
|
|
'excerpt' => 'A cleanup checklist for exporting Academy-ready artwork to Skinbase.',
|
|
'content' => 'Check crop, upscale carefully, fix edge artifacts, and export a final image that fits the target category and composition.',
|
|
'difficulty' => 'beginner',
|
|
'access_level' => 'free',
|
|
'lesson_type' => 'workflow',
|
|
'featured' => false,
|
|
],
|
|
[
|
|
'slug' => 'advanced-wallpaper-prompt-engineering',
|
|
'category_slug' => 'wallpapers',
|
|
'title' => 'Advanced Wallpaper Prompt Engineering',
|
|
'excerpt' => 'Build prompts that control focal depth, desktop negative space, and repeatable atmosphere.',
|
|
'content' => 'Use layered subject directives, desktop-safe composition notes, and finishing instructions to keep wallpapers clean and reusable.',
|
|
'difficulty' => 'advanced',
|
|
'access_level' => 'creator',
|
|
'lesson_type' => 'workflow',
|
|
'featured' => true,
|
|
],
|
|
[
|
|
'slug' => 'creating-consistent-robot-mascots',
|
|
'category_slug' => 'sci-fi',
|
|
'title' => 'Creating Consistent Robot Mascots',
|
|
'excerpt' => 'Keep mascot silhouettes, palettes, and expression readable across multiple prompt iterations.',
|
|
'content' => 'Define anchor traits first, then preserve them with repeated descriptors and a fixed framing recipe across generations.',
|
|
'difficulty' => 'advanced',
|
|
'access_level' => 'creator',
|
|
'lesson_type' => 'workflow',
|
|
'featured' => false,
|
|
],
|
|
[
|
|
'slug' => 'building-a-skinbase-world-from-scratch',
|
|
'category_slug' => 'skinbase-worlds',
|
|
'title' => 'Building a Skinbase World From Scratch',
|
|
'excerpt' => 'Plan a world cover, atmosphere kit, and visual language that feels coherent beyond one image.',
|
|
'content' => 'Start from a world premise, define color anchors, then generate covers, teaser crops, and supporting scenes that share the same visual DNA.',
|
|
'difficulty' => 'pro',
|
|
'access_level' => 'pro',
|
|
'lesson_type' => 'workflow',
|
|
'featured' => true,
|
|
],
|
|
[
|
|
'slug' => 'creating-editorial-news-cover-images',
|
|
'category_slug' => 'news-covers',
|
|
'title' => 'Creating Editorial News Cover Images',
|
|
'excerpt' => 'Design news cover art that reads fast, supports headlines, and avoids clutter.',
|
|
'content' => 'Compose with headline space in mind, simplify the focal idea, and leave enough structure for editorial overlays to stay readable.',
|
|
'difficulty' => 'pro',
|
|
'access_level' => 'pro',
|
|
'lesson_type' => 'workflow',
|
|
'featured' => false,
|
|
],
|
|
];
|
|
|
|
foreach ($lessons as $index => $lesson) {
|
|
$academyLesson = AcademyLesson::query()->updateOrCreate(
|
|
['slug' => $lesson['slug']],
|
|
[
|
|
'category_id' => $categories->get($lesson['category_slug'])?->id,
|
|
'title' => $lesson['title'],
|
|
'excerpt' => $lesson['excerpt'],
|
|
'content' => $lesson['content'],
|
|
'difficulty' => $lesson['difficulty'],
|
|
'access_level' => $lesson['access_level'],
|
|
'lesson_type' => $lesson['lesson_type'],
|
|
'featured' => $lesson['featured'],
|
|
'active' => true,
|
|
'published_at' => now()->subDays(8 - $index),
|
|
],
|
|
);
|
|
|
|
if ($lesson['slug'] === 'what-is-ai-assisted-digital-art') {
|
|
AcademyLessonBlock::query()->updateOrCreate(
|
|
[
|
|
'lesson_id' => $academyLesson->id,
|
|
'type' => 'ai_comparison',
|
|
'sort_order' => 0,
|
|
],
|
|
[
|
|
'title' => 'Same Prompt, Different AI Models',
|
|
'payload' => [
|
|
'title' => 'Same Prompt, Different AI Models',
|
|
'intro' => 'We used the same fantasy forest prompt in different AI image tools to compare how each model handles mood, composition, detail, lighting, and wallpaper quality.',
|
|
'prompt' => 'A peaceful fantasy forest wallpaper, glowing blue flowers, soft morning light, gentle mist, wide cinematic composition, detailed digital painting, calm mood, high-resolution wallpaper, no text, no watermark.',
|
|
'negative_prompt' => 'text, watermark, blurry pixels, distorted objects, bad anatomy, modern UI',
|
|
'aspect_ratio' => '16:9',
|
|
'criteria' => [
|
|
'Composition',
|
|
'Lighting',
|
|
'Wallpaper quality',
|
|
'Prompt accuracy',
|
|
'Detail quality',
|
|
'Beginner friendliness',
|
|
],
|
|
],
|
|
'active' => true,
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
$prompts = [
|
|
[
|
|
'slug' => 'fantasy-floating-island-wallpaper',
|
|
'category_slug' => 'fantasy',
|
|
'title' => 'Fantasy Floating Island Wallpaper',
|
|
'excerpt' => 'A cinematic floating-island prompt for wide wallpaper compositions.',
|
|
'prompt' => 'A cinematic fantasy floating island above glowing clouds, ancient ruins, waterfalls falling into the sky, sunrise, dramatic lighting, ultra detailed digital painting.',
|
|
'negative_prompt' => 'blurry, low quality, watermark, text, noisy image',
|
|
'difficulty' => 'beginner',
|
|
'access_level' => 'creator',
|
|
'aspect_ratio' => '16:9',
|
|
'tags' => ['fantasy', 'wallpaper', 'floating island'],
|
|
'featured' => true,
|
|
'prompt_of_week' => true,
|
|
],
|
|
[
|
|
'slug' => 'sci-fi-robot-mascot-scene',
|
|
'category_slug' => 'sci-fi',
|
|
'title' => 'Sci-Fi Robot Mascot Scene',
|
|
'excerpt' => 'A prompt recipe for a polished Skinbase-style mascot reveal scene.',
|
|
'prompt' => 'Friendly futuristic robot mascot in a sleek digital gallery, cinematic rim light, crisp silhouette, polished sci-fi materials, editorial composition.',
|
|
'negative_prompt' => 'duplicate limbs, muddy details, unreadable face, text, watermark',
|
|
'difficulty' => 'intermediate',
|
|
'access_level' => 'creator',
|
|
'aspect_ratio' => '16:9',
|
|
'tags' => ['sci-fi', 'robot', 'mascot'],
|
|
'featured' => true,
|
|
'prompt_of_week' => false,
|
|
],
|
|
[
|
|
'slug' => 'amiga-pixel-art-island',
|
|
'category_slug' => 'pixel-art',
|
|
'title' => 'Amiga Pixel Art Island',
|
|
'excerpt' => 'A nostalgic pixel-art prompt tuned for an Amiga-inspired island scene.',
|
|
'prompt' => 'Retro Amiga-inspired pixel art island, chunky palette, bright shoreline, palm trees, crisp dithering, overhead scene composition.',
|
|
'negative_prompt' => 'smooth gradients, modern UI, blurry pixels, text, watermark',
|
|
'difficulty' => 'beginner',
|
|
'access_level' => 'free',
|
|
'aspect_ratio' => '4:3',
|
|
'tags' => ['pixel art', 'amiga', 'island'],
|
|
'featured' => false,
|
|
'prompt_of_week' => false,
|
|
],
|
|
[
|
|
'slug' => 'hello-again-world-cover',
|
|
'category_slug' => 'fantasy',
|
|
'title' => 'Hello Again World Cover',
|
|
'excerpt' => 'A hopeful world-cover prompt for relaunch and rebirth themes.',
|
|
'prompt' => 'Hopeful rebirth world cover, luminous horizon, layered clouds, visual depth, centered emblem space, cinematic optimism.',
|
|
'negative_prompt' => 'dark horror tone, cluttered foreground, low detail, text, watermark',
|
|
'difficulty' => 'intermediate',
|
|
'access_level' => 'free',
|
|
'aspect_ratio' => '16:9',
|
|
'tags' => ['world cover', 'hopeful', 'rebirth'],
|
|
'featured' => false,
|
|
'prompt_of_week' => false,
|
|
],
|
|
[
|
|
'slug' => 'spring-vibes-meadow',
|
|
'category_slug' => 'fantasy',
|
|
'title' => 'Spring Vibes Meadow',
|
|
'excerpt' => 'A bright meadow prompt with clean wallpaper composition and airy color direction.',
|
|
'prompt' => 'Spring meadow wallpaper, soft golden light, airy depth, blooming flowers, gentle wind, clean composition for desktop background.',
|
|
'negative_prompt' => 'muddy colors, clutter, overexposed sky, text, watermark',
|
|
'difficulty' => 'beginner',
|
|
'access_level' => 'free',
|
|
'aspect_ratio' => '16:9',
|
|
'tags' => ['spring', 'meadow', 'wallpaper'],
|
|
'featured' => false,
|
|
'prompt_of_week' => false,
|
|
],
|
|
[
|
|
'slug' => 'ai-news-cover-image',
|
|
'category_slug' => 'sci-fi',
|
|
'title' => 'AI News Cover Image',
|
|
'excerpt' => 'A structured prompt for editorial cover art with clear subject hierarchy.',
|
|
'prompt' => 'Editorial AI news cover, strong focal subject, clean negative space for title overlay, sleek modern composition, dramatic but readable lighting.',
|
|
'negative_prompt' => 'busy background, unreadable subject, headline text, watermark, logo',
|
|
'difficulty' => 'advanced',
|
|
'access_level' => 'pro',
|
|
'aspect_ratio' => '3:2',
|
|
'tags' => ['news cover', 'editorial', 'ai art'],
|
|
'featured' => true,
|
|
'prompt_of_week' => false,
|
|
],
|
|
];
|
|
|
|
$promptIdsBySlug = [];
|
|
|
|
foreach ($prompts as $index => $prompt) {
|
|
$record = AcademyPromptTemplate::query()->updateOrCreate(
|
|
['slug' => $prompt['slug']],
|
|
[
|
|
'category_id' => $categories->get($prompt['category_slug'])?->id,
|
|
'title' => $prompt['title'],
|
|
'excerpt' => $prompt['excerpt'],
|
|
'prompt' => $prompt['prompt'],
|
|
'negative_prompt' => $prompt['negative_prompt'],
|
|
'difficulty' => $prompt['difficulty'],
|
|
'access_level' => $prompt['access_level'],
|
|
'aspect_ratio' => $prompt['aspect_ratio'],
|
|
'tags' => $prompt['tags'],
|
|
'featured' => $prompt['featured'],
|
|
'prompt_of_week' => $prompt['prompt_of_week'],
|
|
'active' => true,
|
|
'published_at' => now()->subDays(6 - $index),
|
|
],
|
|
);
|
|
|
|
$promptIdsBySlug[$prompt['slug']] = $record->id;
|
|
}
|
|
|
|
$packs = [
|
|
[
|
|
'slug' => 'wallpaper-starter-pack',
|
|
'title' => 'Wallpaper Starter Pack',
|
|
'excerpt' => 'A first bundle of Academy prompt templates for wallpaper-focused creators.',
|
|
'description' => 'Starter bundle for creators who want reusable composition and atmosphere prompts for desktop-ready work.',
|
|
'access_level' => 'creator',
|
|
'featured' => true,
|
|
'prompt_slugs' => ['fantasy-floating-island-wallpaper', 'spring-vibes-meadow'],
|
|
],
|
|
[
|
|
'slug' => 'hello-again-world-builder-pack',
|
|
'title' => 'Hello Again World Builder Pack',
|
|
'excerpt' => 'A focused set of prompts for world covers, teaser art, and relaunch atmosphere.',
|
|
'description' => 'Built for Skinbase Worlds concepts, relaunch visuals, and hopeful teaser compositions.',
|
|
'access_level' => 'creator',
|
|
'featured' => false,
|
|
'prompt_slugs' => ['hello-again-world-cover', 'fantasy-floating-island-wallpaper'],
|
|
],
|
|
[
|
|
'slug' => 'fantasy-realms-prompt-pack',
|
|
'title' => 'Fantasy Realms Prompt Pack',
|
|
'excerpt' => 'Premium fantasy prompts for scenic covers and high-detail digital worlds.',
|
|
'description' => 'A denser fantasy pack for creators building larger scene families and cover variants.',
|
|
'access_level' => 'pro',
|
|
'featured' => true,
|
|
'prompt_slugs' => ['fantasy-floating-island-wallpaper', 'hello-again-world-cover'],
|
|
],
|
|
];
|
|
|
|
foreach ($packs as $packData) {
|
|
$pack = AcademyPromptPack::query()->updateOrCreate(
|
|
['slug' => $packData['slug']],
|
|
[
|
|
'title' => $packData['title'],
|
|
'excerpt' => $packData['excerpt'],
|
|
'description' => $packData['description'],
|
|
'access_level' => $packData['access_level'],
|
|
'featured' => $packData['featured'],
|
|
'active' => true,
|
|
'published_at' => now()->subDay(),
|
|
],
|
|
);
|
|
|
|
foreach ($packData['prompt_slugs'] as $order => $promptSlug) {
|
|
if (! isset($promptIdsBySlug[$promptSlug])) {
|
|
continue;
|
|
}
|
|
|
|
AcademyPromptPackItem::query()->updateOrCreate(
|
|
['pack_id' => $pack->id, 'prompt_template_id' => $promptIdsBySlug[$promptSlug]],
|
|
['order_num' => $order],
|
|
);
|
|
}
|
|
}
|
|
|
|
$challenges = [
|
|
[
|
|
'slug' => 'hello-again-create-a-rebirth-wallpaper',
|
|
'title' => 'Hello Again: Create a Rebirth Wallpaper',
|
|
'excerpt' => 'Create a launch-era wallpaper using bright skies, hopeful atmosphere, and a strong desktop composition.',
|
|
'description' => 'An Academy launch brief focused on optimistic wallpaper composition and Skinbase-style color direction.',
|
|
'brief' => 'Create a wallpaper that communicates return, energy, and visual clarity.',
|
|
'rules' => 'Use original prompts and clearly mark AI-assisted workflow details.',
|
|
'access_level' => 'free',
|
|
'required_tags' => ['academy', 'rebirth'],
|
|
'allowed_categories' => ['wallpapers', 'prompting-basics'],
|
|
'featured' => true,
|
|
],
|
|
[
|
|
'slug' => 'fantasy-realms-build-a-magical-world',
|
|
'title' => 'Fantasy Realms: Build a Magical World',
|
|
'excerpt' => 'Design a fantasy cover or world scene with readable atmosphere and strong visual storytelling.',
|
|
'description' => 'A challenge built around fantasy world-building, magical landscapes, and cover-ready imagery.',
|
|
'brief' => 'Develop a magical world scene with a clear horizon, mood, and focal subject.',
|
|
'rules' => 'Original prompts only. Keep the composition upload-ready and explain your workflow briefly.',
|
|
'access_level' => 'creator',
|
|
'required_tags' => ['academy', 'fantasy-realms'],
|
|
'allowed_categories' => ['fantasy', 'skinbase-worlds'],
|
|
'featured' => true,
|
|
],
|
|
[
|
|
'slug' => 'amiga-memories-pixel-art-challenge',
|
|
'title' => 'Amiga Memories: Pixel Art Challenge',
|
|
'excerpt' => 'Use retro palettes and strong pixel readability to build a nostalgic island or world scene.',
|
|
'description' => 'A retro prompt challenge with strict readability, palette discipline, and nostalgic energy.',
|
|
'brief' => 'Create an Amiga-inspired pixel scene that feels coherent at thumbnail and full size.',
|
|
'rules' => 'Stay readable, avoid smooth gradients, and describe any manual cleanup in your notes.',
|
|
'access_level' => 'free',
|
|
'required_tags' => ['academy', 'pixel-art'],
|
|
'allowed_categories' => ['pixel-art'],
|
|
'featured' => false,
|
|
],
|
|
];
|
|
|
|
foreach ($challenges as $index => $challenge) {
|
|
AcademyChallenge::query()->updateOrCreate(
|
|
['slug' => $challenge['slug']],
|
|
[
|
|
'title' => $challenge['title'],
|
|
'excerpt' => $challenge['excerpt'],
|
|
'description' => $challenge['description'],
|
|
'brief' => $challenge['brief'],
|
|
'rules' => $challenge['rules'],
|
|
'access_level' => $challenge['access_level'],
|
|
'status' => 'active',
|
|
'starts_at' => now()->subDays(2 + $index),
|
|
'ends_at' => now()->addDays(10 + $index),
|
|
'required_tags' => $challenge['required_tags'],
|
|
'allowed_categories' => $challenge['allowed_categories'],
|
|
'featured' => $challenge['featured'],
|
|
'active' => true,
|
|
],
|
|
);
|
|
}
|
|
|
|
$badges = [
|
|
[
|
|
'slug' => 'ai-academy-explorer',
|
|
'name' => 'AI Academy Explorer',
|
|
'description' => 'Awarded for participating in Skinbase AI Academy as a free learner.',
|
|
'badge_type' => 'plan',
|
|
'rules' => ['access_level' => 'free'],
|
|
],
|
|
[
|
|
'slug' => 'ai-academy-creator',
|
|
'name' => 'AI Academy Creator',
|
|
'description' => 'Awarded to Creator-tier Academy members.',
|
|
'badge_type' => 'plan',
|
|
'rules' => ['access_level' => 'creator'],
|
|
],
|
|
[
|
|
'slug' => 'ai-academy-pro',
|
|
'name' => 'AI Academy Pro',
|
|
'description' => 'Awarded to Pro-tier Academy members.',
|
|
'badge_type' => 'plan',
|
|
'rules' => ['access_level' => 'pro'],
|
|
],
|
|
[
|
|
'slug' => 'prompt-beginner',
|
|
'name' => 'Prompt Beginner',
|
|
'description' => 'Awarded after saving your first Academy prompt.',
|
|
'badge_type' => 'achievement',
|
|
'rules' => ['save_prompts' => 1],
|
|
],
|
|
[
|
|
'slug' => 'world-builder',
|
|
'name' => 'World Builder',
|
|
'description' => 'Awarded after completing World-focused Academy content.',
|
|
'badge_type' => 'achievement',
|
|
'rules' => ['complete_world_lessons' => 1],
|
|
],
|
|
[
|
|
'slug' => 'challenge-participant',
|
|
'name' => 'Challenge Participant',
|
|
'description' => 'Awarded after submitting to an Academy challenge.',
|
|
'badge_type' => 'challenge',
|
|
'rules' => ['submit_challenges' => 1],
|
|
],
|
|
];
|
|
|
|
foreach ($badges as $badge) {
|
|
AcademyBadge::query()->updateOrCreate(
|
|
['slug' => $badge['slug']],
|
|
[
|
|
'name' => $badge['name'],
|
|
'description' => $badge['description'],
|
|
'badge_type' => $badge['badge_type'],
|
|
'rules' => $badge['rules'],
|
|
'active' => true,
|
|
],
|
|
);
|
|
}
|
|
|
|
app(AcademyCacheService::class)->clearAll();
|
|
}
|
|
}
|