- Create robots.txt to allow all user agents and specify sitemap location - Add site.webmanifest for PWA support with app details - Initialize sitemap.xml with the homepage URL and metadata - Set up svelte.config.js for SvelteKit with static adapter and prerendering - Configure TypeScript with tsconfig.json for strict type checking and module resolution - Establish Vite configuration in vite.config.ts for SvelteKit integration
1247 lines
24 KiB
Markdown
1247 lines
24 KiB
Markdown
# Squiggleverse Landing Page Design Document / Spec Sheet
|
||
|
||
## 1. Project Summary
|
||
|
||
**Project:** Squiggleverse landing page
|
||
**Primary goal:** Present Squiggleverse as a whimsical, polished, education-through-play platform using a simple, high-performing homepage structure.
|
||
|
||
**Recommended layout:**
|
||
|
||
1. Logo / hero branding
|
||
2. Embedded or self-hosted promo video
|
||
3. Short explanatory text
|
||
4. Optional CTA row: “Watch Demo,” “Join Mailing List,” “Contact Us”
|
||
|
||
**Core positioning text:**
|
||
|
||
> Squiggleverse is a modular, multi-platform, game-based “stealth” learning system that teaches grammar, usage, and style through innovative gameplay, whimsical characters, and creative narratives co-authored by the player.
|
||
|
||
The page should feel like a lightweight marketing splash page rather than a heavy SaaS homepage.
|
||
|
||
---
|
||
|
||
## 2. Recommended Web Stack
|
||
|
||
### Framework
|
||
|
||
Use **SvelteKit** as the primary framework.
|
||
|
||
SvelteKit is appropriate here because the landing page can be statically rendered, very fast, SEO-friendly, and simple to deploy. SvelteKit supports prerendering/static generation and server-side rendering options per route, which is ideal for a marketing page that may later grow into a larger app or dashboard.
|
||
|
||
### Suggested stack
|
||
|
||
```txt
|
||
SvelteKit
|
||
TypeScript
|
||
Vite
|
||
CSS / SCSS / PostCSS
|
||
Static adapter or platform adapter
|
||
PNPM
|
||
ESLint + Prettier
|
||
```
|
||
|
||
### Deployment targets
|
||
|
||
Good options:
|
||
|
||
```txt
|
||
Cloudflare Pages
|
||
Netlify
|
||
Vercel
|
||
Static hosting behind nginx/Caddy
|
||
CapRover container deployment
|
||
```
|
||
|
||
For this page, **static generation is preferred** unless the site needs dynamic personalization, server-side forms, authentication, or CMS previews.
|
||
|
||
Recommended SvelteKit page config:
|
||
|
||
```ts
|
||
// src/routes/+page.ts
|
||
export const prerender = true;
|
||
export const ssr = true;
|
||
```
|
||
|
||
For a landing page, keep SSR/prerendering enabled so the logo, text, metadata, and canonical content are present in the initial HTML.
|
||
|
||
---
|
||
|
||
## 3. Page Structure
|
||
|
||
### Route
|
||
|
||
```txt
|
||
/
|
||
```
|
||
|
||
### File layout
|
||
|
||
```txt
|
||
src/
|
||
lib/
|
||
assets/
|
||
squiggleverse-logo.webp
|
||
squiggleverse-bg.webp
|
||
squiggleverse-poster.webp
|
||
squiggleverse-demo.mp4
|
||
components/
|
||
HeroLogo.svelte
|
||
VideoCard.svelte
|
||
IntroText.svelte
|
||
CTAButtons.svelte
|
||
StarBackground.svelte
|
||
routes/
|
||
+layout.svelte
|
||
+layout.ts
|
||
+page.svelte
|
||
+page.ts
|
||
+error.svelte
|
||
app.html
|
||
app.css
|
||
static/
|
||
favicon.svg
|
||
robots.txt
|
||
site.webmanifest
|
||
og-image.webp
|
||
```
|
||
|
||
---
|
||
|
||
## 4. Visual Design Direction
|
||
|
||
### Overall style
|
||
|
||
The landing page should use:
|
||
|
||
```txt
|
||
Whimsical
|
||
Space-themed
|
||
Purple/violet palette
|
||
Soft glow effects
|
||
Rounded cards
|
||
Centered single-column layout
|
||
Large readable text
|
||
Minimal navigation
|
||
```
|
||
|
||
### Layout wireframe
|
||
|
||
```txt
|
||
┌─────────────────────────────────────┐
|
||
│ │
|
||
│ Logo │
|
||
│ │
|
||
│ ┌───────────────────┐ │
|
||
│ │ │ │
|
||
│ │ Video │ │
|
||
│ │ │ │
|
||
│ └───────────────────┘ │
|
||
│ │
|
||
│ Short description text │
|
||
│ │
|
||
│ [ Watch Demo ] [ Contact ] │
|
||
│ │
|
||
└─────────────────────────────────────┘
|
||
```
|
||
|
||
### Responsive behavior
|
||
|
||
#### Desktop
|
||
|
||
```txt
|
||
Max content width: 960–1100px
|
||
Logo width: 520–720px
|
||
Video width: 800–960px
|
||
Text width: 680–820px
|
||
```
|
||
|
||
#### Tablet
|
||
|
||
```txt
|
||
Content width: 90vw
|
||
Logo width: 70–80vw
|
||
Video width: 90vw
|
||
Text width: 80–90vw
|
||
```
|
||
|
||
#### Mobile
|
||
|
||
```txt
|
||
Single column
|
||
Logo width: 86vw
|
||
Video width: 92vw
|
||
Text centered or slightly left-aligned if readability suffers
|
||
Font size reduced carefully
|
||
```
|
||
|
||
---
|
||
|
||
## 5. Color System
|
||
|
||
Use a constrained purple palette.
|
||
|
||
```css
|
||
:root {
|
||
--color-bg-deep: #070014;
|
||
--color-bg-space: #160030;
|
||
--color-purple-dark: #2a0f56;
|
||
--color-purple: #6b3fb3;
|
||
--color-purple-light: #b58cff;
|
||
--color-lavender: #f1e7ff;
|
||
--color-white: #ffffff;
|
||
--color-cyan-accent: #43d8ff;
|
||
|
||
--glow-purple: 0 0 32px rgba(159, 95, 255, 0.45);
|
||
--border-purple: rgba(190, 143, 255, 0.38);
|
||
}
|
||
```
|
||
|
||
### Background
|
||
|
||
Use the provided starry background as a fullscreen visual layer.
|
||
|
||
Recommended CSS:
|
||
|
||
```css
|
||
.page {
|
||
min-height: 100svh;
|
||
background:
|
||
linear-gradient(
|
||
to bottom,
|
||
rgba(7, 0, 20, 0.2),
|
||
rgba(54, 0, 95, 0.35)
|
||
),
|
||
url('/assets/squiggleverse-bg.webp');
|
||
background-size: cover;
|
||
background-position: center top;
|
||
background-attachment: fixed;
|
||
}
|
||
```
|
||
|
||
For mobile, avoid `background-attachment: fixed` because it can cause jank.
|
||
|
||
```css
|
||
@media (max-width: 768px) {
|
||
.page {
|
||
background-attachment: scroll;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 6. Typography
|
||
|
||
### Primary recommendation
|
||
|
||
Use a highly readable sans-serif for body copy.
|
||
|
||
Good options:
|
||
|
||
```txt
|
||
Atkinson Hyperlegible
|
||
Nunito Sans
|
||
Inter
|
||
Lexend
|
||
Source Sans 3
|
||
```
|
||
|
||
For an educational product, **Atkinson Hyperlegible** or **Lexend** would fit well because they emphasize readability.
|
||
|
||
### Font loading
|
||
|
||
Prefer self-hosted fonts using `@font-face`.
|
||
|
||
```css
|
||
@font-face {
|
||
font-family: 'Atkinson Hyperlegible';
|
||
src: url('/fonts/AtkinsonHyperlegible-Regular.woff2') format('woff2');
|
||
font-weight: 400;
|
||
font-display: swap;
|
||
}
|
||
```
|
||
|
||
Use `font-display: swap` to avoid invisible text during load.
|
||
|
||
---
|
||
|
||
## 7. Component Specification
|
||
|
||
### `HeroLogo.svelte`
|
||
|
||
Purpose:
|
||
|
||
```txt
|
||
Displays the Squiggleverse logo centered at the top.
|
||
```
|
||
|
||
Requirements:
|
||
|
||
```txt
|
||
Use actual provided logo asset.
|
||
Do not recreate the logo in text.
|
||
Use responsive sizing.
|
||
Include alt text.
|
||
Avoid layout shift by declaring width/height or aspect ratio.
|
||
```
|
||
|
||
Example:
|
||
|
||
```svelte
|
||
<script lang="ts">
|
||
import logo from '$lib/assets/squiggleverse-logo.webp';
|
||
</script>
|
||
|
||
<div class="hero-logo">
|
||
<img
|
||
src={logo}
|
||
alt="Squiggleverse"
|
||
width="900"
|
||
height="420"
|
||
decoding="async"
|
||
/>
|
||
</div>
|
||
```
|
||
|
||
CSS:
|
||
|
||
```css
|
||
.hero-logo {
|
||
display: flex;
|
||
justify-content: center;
|
||
margin-inline: auto;
|
||
}
|
||
|
||
.hero-logo img {
|
||
width: min(720px, 88vw);
|
||
height: auto;
|
||
filter: drop-shadow(0 0 28px rgba(159, 95, 255, 0.45));
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### `VideoCard.svelte`
|
||
|
||
Purpose:
|
||
|
||
```txt
|
||
Displays the main Squiggleverse video or poster/video preview.
|
||
```
|
||
|
||
Preferred implementation:
|
||
|
||
```txt
|
||
Use native <video> for self-hosted promo video.
|
||
Use poster image.
|
||
Lazy-load if below fold, but in this layout it is likely above fold.
|
||
Avoid YouTube iframe unless necessary.
|
||
```
|
||
|
||
Native video gives better branding control, fewer third-party scripts, and better privacy/performance.
|
||
|
||
Example:
|
||
|
||
```svelte
|
||
<script lang="ts">
|
||
import poster from '$lib/assets/squiggleverse-poster.webp';
|
||
import video from '$lib/assets/squiggleverse-demo.mp4';
|
||
</script>
|
||
|
||
<section class="video-card" aria-label="Squiggleverse demo video">
|
||
<video
|
||
controls
|
||
preload="metadata"
|
||
poster={poster}
|
||
playsinline
|
||
>
|
||
<source src={video} type="video/mp4" />
|
||
Your browser does not support the video tag.
|
||
</video>
|
||
</section>
|
||
```
|
||
|
||
CSS:
|
||
|
||
```css
|
||
.video-card {
|
||
width: min(940px, 92vw);
|
||
margin: 2rem auto 2.25rem;
|
||
padding: clamp(0.5rem, 1.2vw, 0.9rem);
|
||
border: 1px solid var(--border-purple);
|
||
border-radius: 2rem;
|
||
background:
|
||
linear-gradient(
|
||
180deg,
|
||
rgba(28, 10, 72, 0.72),
|
||
rgba(12, 4, 38, 0.78)
|
||
);
|
||
box-shadow:
|
||
var(--glow-purple),
|
||
inset 0 0 40px rgba(255, 255, 255, 0.04);
|
||
backdrop-filter: blur(8px);
|
||
}
|
||
|
||
.video-card video {
|
||
display: block;
|
||
width: 100%;
|
||
aspect-ratio: 16 / 9;
|
||
border-radius: 1.45rem;
|
||
background: #090019;
|
||
}
|
||
```
|
||
|
||
### Video asset requirements
|
||
|
||
```txt
|
||
Format: MP4/H.264 baseline or high profile
|
||
Optional: WebM VP9/AV1 for modern browsers
|
||
Poster: WebP or AVIF
|
||
Resolution: 1280×720 minimum
|
||
Max video size target: 3–8 MB for landing page
|
||
Audio: compressed AAC, normalized
|
||
Captions: WebVTT file if voiceover exists
|
||
```
|
||
|
||
Add captions if there is spoken content:
|
||
|
||
```svelte
|
||
<track
|
||
kind="captions"
|
||
src="/captions/squiggleverse-demo.vtt"
|
||
srclang="en"
|
||
label="English"
|
||
/>
|
||
```
|
||
|
||
---
|
||
|
||
### `IntroText.svelte`
|
||
|
||
Purpose:
|
||
|
||
```txt
|
||
Displays the main product positioning copy.
|
||
```
|
||
|
||
Requirements:
|
||
|
||
```txt
|
||
Exact text preserved.
|
||
Readable line length.
|
||
High contrast.
|
||
No image-rendered text.
|
||
```
|
||
|
||
Example:
|
||
|
||
```svelte
|
||
<section class="intro" aria-labelledby="intro-title">
|
||
<h1 id="intro-title" class="sr-only">About Squiggleverse</h1>
|
||
|
||
<p>
|
||
Squiggleverse is a modular, multi-platform, game-based “stealth” learning
|
||
system that teaches grammar, usage, and style through innovative gameplay,
|
||
whimsical characters, and creative narratives co-authored by the player.
|
||
</p>
|
||
</section>
|
||
```
|
||
|
||
CSS:
|
||
|
||
```css
|
||
.intro {
|
||
width: min(820px, 88vw);
|
||
margin: 0 auto;
|
||
text-align: center;
|
||
}
|
||
|
||
.intro p {
|
||
margin: 0;
|
||
color: var(--color-lavender);
|
||
font-size: clamp(1.2rem, 2.2vw, 2rem);
|
||
line-height: 1.45;
|
||
letter-spacing: 0.01em;
|
||
text-shadow: 0 2px 18px rgba(0, 0, 0, 0.45);
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### Optional `CTAButtons.svelte`
|
||
|
||
Even if the initial page is simple, adding a CTA is useful for conversion.
|
||
|
||
Recommended CTAs:
|
||
|
||
```txt
|
||
Primary: Watch Demo
|
||
Secondary: Contact Us
|
||
Optional: Join Mailing List
|
||
```
|
||
|
||
Example:
|
||
|
||
```svelte
|
||
<div class="cta-row">
|
||
<a class="button button-primary" href="#demo">Watch Demo</a>
|
||
<a class="button button-secondary" href="mailto:hello@squiggleverse.com">
|
||
Contact Us
|
||
</a>
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
## 8. Accessibility Requirements
|
||
|
||
### Required
|
||
|
||
```txt
|
||
Logo must have meaningful alt text.
|
||
Video must have controls.
|
||
Video needs captions if it contains speech.
|
||
Text must not be baked into images.
|
||
All interactive elements need visible focus states.
|
||
Color contrast should meet WCAG AA.
|
||
Animations/glows should respect prefers-reduced-motion.
|
||
Page must be keyboard navigable.
|
||
```
|
||
|
||
### Reduced motion
|
||
|
||
```css
|
||
@media (prefers-reduced-motion: reduce) {
|
||
*,
|
||
*::before,
|
||
*::after {
|
||
animation-duration: 0.001ms !important;
|
||
animation-iteration-count: 1 !important;
|
||
scroll-behavior: auto !important;
|
||
}
|
||
}
|
||
```
|
||
|
||
### Focus styling
|
||
|
||
```css
|
||
:focus-visible {
|
||
outline: 3px solid var(--color-cyan-accent);
|
||
outline-offset: 4px;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 9. SEO Specification
|
||
|
||
### Rendering
|
||
|
||
Use prerendered HTML for the homepage. Search engines should receive real text content, not an empty SPA shell. SvelteKit can prerender static routes into static files, which fits this use case well.
|
||
|
||
### Metadata
|
||
|
||
Implement in `+page.svelte`:
|
||
|
||
```svelte
|
||
<svelte:head>
|
||
<title>Squiggleverse | Game-Based Grammar, Usage, and Style Learning</title>
|
||
<meta
|
||
name="description"
|
||
content="Squiggleverse is a modular, multi-platform, game-based stealth learning system for grammar, usage, and style."
|
||
/>
|
||
<link rel="canonical" href="https://squiggleverse.com/" />
|
||
|
||
<meta property="og:type" content="website" />
|
||
<meta property="og:title" content="Squiggleverse" />
|
||
<meta
|
||
property="og:description"
|
||
content="A whimsical game-based learning system for grammar, usage, and style."
|
||
/>
|
||
<meta property="og:image" content="https://squiggleverse.com/og-image.webp" />
|
||
<meta property="og:url" content="https://squiggleverse.com/" />
|
||
|
||
<meta name="twitter:card" content="summary_large_image" />
|
||
<meta name="twitter:title" content="Squiggleverse" />
|
||
<meta
|
||
name="twitter:description"
|
||
content="A whimsical game-based learning system for grammar, usage, and style."
|
||
/>
|
||
<meta name="twitter:image" content="https://squiggleverse.com/og-image.webp" />
|
||
</svelte:head>
|
||
```
|
||
|
||
### Suggested title variants
|
||
|
||
```txt
|
||
Squiggleverse | Game-Based Grammar Learning
|
||
Squiggleverse | Learn Grammar Through Play
|
||
Squiggleverse | Stealth Learning Through Whimsical Gameplay
|
||
```
|
||
|
||
### Suggested meta description
|
||
|
||
```txt
|
||
Squiggleverse is a modular, multi-platform, game-based stealth learning system that teaches grammar, usage, and style through whimsical gameplay.
|
||
```
|
||
|
||
Keep meta descriptions around 140–160 characters when possible.
|
||
|
||
### Heading structure
|
||
|
||
Recommended:
|
||
|
||
```html
|
||
<h1>Squiggleverse</h1>
|
||
```
|
||
|
||
Because the logo is graphical, include a visually hidden H1.
|
||
|
||
```svelte
|
||
<h1 class="sr-only">Squiggleverse</h1>
|
||
```
|
||
|
||
Use only one H1 on the page.
|
||
|
||
### Structured data
|
||
|
||
Add basic `WebSite` and `Organization` JSON-LD.
|
||
|
||
```svelte
|
||
<svelte:head>
|
||
<script type="application/ld+json">
|
||
{JSON.stringify({
|
||
'@context': 'https://schema.org',
|
||
'@type': 'WebSite',
|
||
name: 'Squiggleverse',
|
||
url: 'https://squiggleverse.com/',
|
||
description:
|
||
'A modular, multi-platform, game-based stealth learning system for grammar, usage, and style.'
|
||
})}
|
||
</script>
|
||
</svelte:head>
|
||
```
|
||
|
||
If a company/entity name exists, add `Organization`.
|
||
|
||
### Robots
|
||
|
||
`static/robots.txt`:
|
||
|
||
```txt
|
||
User-agent: *
|
||
Allow: /
|
||
|
||
Sitemap: https://squiggleverse.com/sitemap.xml
|
||
```
|
||
|
||
### Sitemap
|
||
|
||
For one page, the sitemap is simple:
|
||
|
||
```xml
|
||
<?xml version="1.0" encoding="UTF-8"?>
|
||
<urlset xmlns="https://www.sitemaps.org/schemas/sitemap/0.9">
|
||
<url>
|
||
<loc>https://squiggleverse.com/</loc>
|
||
<changefreq>monthly</changefreq>
|
||
<priority>1.0</priority>
|
||
</url>
|
||
</urlset>
|
||
```
|
||
|
||
---
|
||
|
||
## 10. Performance Requirements
|
||
|
||
### Core Web Vitals targets
|
||
|
||
Use these targets:
|
||
|
||
```txt
|
||
LCP: ≤ 2.5s
|
||
CLS: ≤ 0.1
|
||
INP: ≤ 200ms
|
||
Total JS: ideally under 100 KB compressed for this page
|
||
Initial image payload: ideally under 500 KB before video
|
||
Video: do not autoplay large media
|
||
```
|
||
|
||
### LCP optimization
|
||
|
||
Likely LCP candidate:
|
||
|
||
```txt
|
||
Logo image
|
||
or
|
||
intro text block
|
||
or
|
||
video poster image
|
||
```
|
||
|
||
Recommendations:
|
||
|
||
```txt
|
||
Use optimized WebP/AVIF.
|
||
Declare image dimensions.
|
||
Preload the logo only if it is the true LCP element.
|
||
Avoid client-only rendering for hero content.
|
||
Do not load heavy JS before first paint.
|
||
```
|
||
|
||
Example preload:
|
||
|
||
```svelte
|
||
<svelte:head>
|
||
<link
|
||
rel="preload"
|
||
as="image"
|
||
href="/assets/squiggleverse-logo.webp"
|
||
type="image/webp"
|
||
/>
|
||
</svelte:head>
|
||
```
|
||
|
||
Only preload the logo if testing confirms it improves LCP.
|
||
|
||
### CLS prevention
|
||
|
||
```txt
|
||
Set width/height on images.
|
||
Use aspect-ratio for video card.
|
||
Avoid late-loading web fonts without fallback sizing.
|
||
Reserve space for video controls/poster.
|
||
Avoid injecting CTA/forms above existing content after hydration.
|
||
```
|
||
|
||
### Video performance
|
||
|
||
Use:
|
||
|
||
```html
|
||
preload="metadata"
|
||
poster="/assets/squiggleverse-poster.webp"
|
||
playsinline
|
||
controls
|
||
```
|
||
|
||
Avoid:
|
||
|
||
```html
|
||
autoplay
|
||
preload="auto"
|
||
large uncompressed MOV files
|
||
third-party iframe on first load
|
||
```
|
||
|
||
If YouTube/Vimeo is required, use a “lite embed” strategy:
|
||
|
||
```txt
|
||
Show poster image first.
|
||
Load iframe only after click.
|
||
```
|
||
|
||
### Image optimization
|
||
|
||
Generate:
|
||
|
||
```txt
|
||
logo.webp
|
||
logo.avif
|
||
background.webp
|
||
background.avif
|
||
poster.webp
|
||
poster.avif
|
||
og-image.webp
|
||
```
|
||
|
||
Recommended sizes:
|
||
|
||
```txt
|
||
Logo: 900–1200 px wide
|
||
Background: 1920 px wide desktop, 960 px mobile variant
|
||
Poster: 1280×720
|
||
OG image: 1200×630
|
||
```
|
||
|
||
Use `srcset` for the background or use CSS media queries.
|
||
|
||
---
|
||
|
||
## 11. Security Specification
|
||
|
||
### Content Security Policy
|
||
|
||
SvelteKit supports CSP configuration that helps restrict where scripts, styles, images, fonts, and other resources can load from. CSP is specifically useful for reducing XSS exposure.
|
||
|
||
Example starter CSP in `svelte.config.js`:
|
||
|
||
```js
|
||
const config = {
|
||
kit: {
|
||
csp: {
|
||
mode: 'auto',
|
||
directives: {
|
||
'default-src': ['self'],
|
||
'script-src': ['self'],
|
||
'style-src': ['self', 'unsafe-inline'],
|
||
'img-src': ['self', 'data:'],
|
||
'font-src': ['self'],
|
||
'media-src': ['self'],
|
||
'connect-src': ['self'],
|
||
'frame-src': ['self'],
|
||
'object-src': ['none'],
|
||
'base-uri': ['self'],
|
||
'form-action': ['self'],
|
||
'frame-ancestors': ['none']
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
export default config;
|
||
```
|
||
|
||
Notes:
|
||
|
||
```txt
|
||
Avoid unsafe-inline for scripts.
|
||
Style unsafe-inline may be necessary depending on SvelteKit output and deployment mode.
|
||
If using YouTube/Vimeo, frame-src and img-src need additional domains.
|
||
If using analytics, connect-src/script-src must include that provider.
|
||
```
|
||
|
||
### Security headers
|
||
|
||
Recommended headers:
|
||
|
||
```txt
|
||
Content-Security-Policy
|
||
Strict-Transport-Security
|
||
X-Content-Type-Options: nosniff
|
||
Referrer-Policy: strict-origin-when-cross-origin
|
||
Permissions-Policy
|
||
X-Frame-Options: DENY or CSP frame-ancestors 'none'
|
||
Cross-Origin-Opener-Policy: same-origin
|
||
```
|
||
|
||
Example SvelteKit hook:
|
||
|
||
```ts
|
||
// src/hooks.server.ts
|
||
import type { Handle } from '@sveltejs/kit';
|
||
|
||
export const handle: Handle = async ({ event, resolve }) => {
|
||
const response = await resolve(event);
|
||
|
||
response.headers.set('X-Content-Type-Options', 'nosniff');
|
||
response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
|
||
response.headers.set(
|
||
'Permissions-Policy',
|
||
'camera=(), microphone=(), geolocation=(), payment=()'
|
||
);
|
||
|
||
return response;
|
||
};
|
||
```
|
||
|
||
For fully static deployment, set these headers at the host/CDN level instead.
|
||
|
||
### Forms
|
||
|
||
If adding a mailing list form:
|
||
|
||
```txt
|
||
Use server-side validation.
|
||
Add rate limiting.
|
||
Use CSRF protection where applicable.
|
||
Never expose API secrets in client-side env vars.
|
||
Use honeypot field or Turnstile/hCaptcha if spam becomes a problem.
|
||
```
|
||
|
||
### Environment variables
|
||
|
||
Use:
|
||
|
||
```txt
|
||
.env
|
||
PRIVATE_*
|
||
PUBLIC_*
|
||
```
|
||
|
||
Do not put API secrets in `PUBLIC_*`.
|
||
|
||
---
|
||
|
||
## 12. Privacy Considerations
|
||
|
||
Recommended:
|
||
|
||
```txt
|
||
Avoid third-party trackers initially.
|
||
Avoid third-party video if possible.
|
||
Self-host fonts.
|
||
Self-host video.
|
||
Self-host images.
|
||
Use privacy-friendly analytics only if needed.
|
||
```
|
||
|
||
Good analytics options:
|
||
|
||
```txt
|
||
Plausible
|
||
Fathom
|
||
Umami self-hosted
|
||
Cloudflare Web Analytics
|
||
No analytics for MVP
|
||
```
|
||
|
||
If analytics are added, update:
|
||
|
||
```txt
|
||
Privacy policy
|
||
Cookie notice if cookies are used
|
||
CSP domains
|
||
```
|
||
|
||
---
|
||
|
||
## 13. SvelteKit Implementation Sketch
|
||
|
||
### `src/routes/+page.svelte`
|
||
|
||
```svelte
|
||
<script lang="ts">
|
||
import HeroLogo from '$lib/components/HeroLogo.svelte';
|
||
import VideoCard from '$lib/components/VideoCard.svelte';
|
||
import IntroText from '$lib/components/IntroText.svelte';
|
||
import CTAButtons from '$lib/components/CTAButtons.svelte';
|
||
</script>
|
||
|
||
<svelte:head>
|
||
<title>Squiggleverse | Game-Based Grammar, Usage, and Style Learning</title>
|
||
<meta
|
||
name="description"
|
||
content="Squiggleverse is a modular, multi-platform, game-based stealth learning system that teaches grammar, usage, and style through whimsical gameplay."
|
||
/>
|
||
<link rel="canonical" href="https://squiggleverse.com/" />
|
||
</svelte:head>
|
||
|
||
<main class="landing-page">
|
||
<h1 class="sr-only">Squiggleverse</h1>
|
||
|
||
<section class="hero" aria-label="Squiggleverse landing page">
|
||
<HeroLogo />
|
||
<VideoCard />
|
||
<IntroText />
|
||
<CTAButtons />
|
||
</section>
|
||
</main>
|
||
```
|
||
|
||
### `src/app.css`
|
||
|
||
```css
|
||
:root {
|
||
color-scheme: dark;
|
||
|
||
--color-bg-deep: #070014;
|
||
--color-bg-space: #160030;
|
||
--color-purple-dark: #2a0f56;
|
||
--color-purple: #6b3fb3;
|
||
--color-purple-light: #b58cff;
|
||
--color-lavender: #f1e7ff;
|
||
--color-white: #ffffff;
|
||
--color-cyan-accent: #43d8ff;
|
||
|
||
--glow-purple: 0 0 32px rgba(159, 95, 255, 0.45);
|
||
--border-purple: rgba(190, 143, 255, 0.38);
|
||
|
||
font-family:
|
||
'Atkinson Hyperlegible',
|
||
system-ui,
|
||
-apple-system,
|
||
BlinkMacSystemFont,
|
||
'Segoe UI',
|
||
sans-serif;
|
||
}
|
||
|
||
html {
|
||
scroll-behavior: smooth;
|
||
}
|
||
|
||
body {
|
||
margin: 0;
|
||
min-width: 320px;
|
||
background: var(--color-bg-deep);
|
||
color: var(--color-white);
|
||
}
|
||
|
||
img,
|
||
video {
|
||
max-width: 100%;
|
||
}
|
||
|
||
.landing-page {
|
||
min-height: 100svh;
|
||
background:
|
||
radial-gradient(circle at top, rgba(123, 69, 202, 0.35), transparent 45%),
|
||
linear-gradient(to bottom, rgba(7, 0, 20, 0.4), rgba(54, 0, 95, 0.45)),
|
||
url('/assets/squiggleverse-bg.webp');
|
||
background-size: cover;
|
||
background-position: center top;
|
||
}
|
||
|
||
.hero {
|
||
width: min(1120px, 100%);
|
||
margin-inline: auto;
|
||
padding: clamp(2rem, 5vw, 4.5rem) 1rem clamp(3rem, 7vw, 6rem);
|
||
}
|
||
|
||
.sr-only {
|
||
position: absolute;
|
||
width: 1px;
|
||
height: 1px;
|
||
overflow: hidden;
|
||
clip-path: inset(50%);
|
||
white-space: nowrap;
|
||
}
|
||
|
||
:focus-visible {
|
||
outline: 3px solid var(--color-cyan-accent);
|
||
outline-offset: 4px;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.landing-page {
|
||
background-attachment: scroll;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 14. Build and Tooling
|
||
|
||
### Package setup
|
||
|
||
```bash
|
||
pnpm create svelte@latest squiggleverse-landing
|
||
cd squiggleverse-landing
|
||
pnpm install
|
||
pnpm dev
|
||
```
|
||
|
||
### Recommended dependencies
|
||
|
||
```bash
|
||
pnpm add -D prettier eslint typescript svelte-check vite
|
||
```
|
||
|
||
Optional:
|
||
|
||
```bash
|
||
pnpm add -D @sveltejs/adapter-static
|
||
```
|
||
|
||
### Static adapter config
|
||
|
||
```js
|
||
// svelte.config.js
|
||
import adapter from '@sveltejs/adapter-static';
|
||
|
||
const config = {
|
||
kit: {
|
||
adapter: adapter({
|
||
pages: 'build',
|
||
assets: 'build',
|
||
fallback: undefined,
|
||
precompress: true,
|
||
strict: true
|
||
})
|
||
}
|
||
};
|
||
|
||
export default config;
|
||
```
|
||
|
||
### Quality checks
|
||
|
||
```bash
|
||
pnpm check
|
||
pnpm lint
|
||
pnpm build
|
||
pnpm preview
|
||
```
|
||
|
||
---
|
||
|
||
## 15. Performance Budget
|
||
|
||
Recommended launch budget:
|
||
|
||
```txt
|
||
HTML: < 30 KB
|
||
CSS: < 50 KB compressed
|
||
JS: < 100 KB compressed
|
||
Logo: < 200 KB
|
||
Background: < 300 KB desktop, < 150 KB mobile
|
||
Poster: < 250 KB
|
||
Video: < 8 MB
|
||
Third-party scripts: 0 initially
|
||
Fonts: < 150 KB total
|
||
```
|
||
|
||
### Testing tools
|
||
|
||
```txt
|
||
Lighthouse
|
||
PageSpeed Insights
|
||
WebPageTest
|
||
Chrome DevTools Performance tab
|
||
SvelteKit build output
|
||
```
|
||
|
||
---
|
||
|
||
## 16. Browser Support
|
||
|
||
Target:
|
||
|
||
```txt
|
||
Latest Chrome
|
||
Latest Firefox
|
||
Latest Safari
|
||
Latest Edge
|
||
iOS Safari
|
||
Android Chrome
|
||
```
|
||
|
||
Graceful degradation:
|
||
|
||
```txt
|
||
No backdrop-filter required for usability.
|
||
No autoplay dependency.
|
||
No JavaScript dependency for reading core page content.
|
||
```
|
||
|
||
---
|
||
|
||
## 17. Content Requirements
|
||
|
||
### Required homepage copy
|
||
|
||
Use exact copy unless changed by brand team:
|
||
|
||
```txt
|
||
Squiggleverse is a modular, multi-platform, game-based “stealth” learning system that teaches grammar, usage, and style through innovative gameplay, whimsical characters, and creative narratives co-authored by the player.
|
||
```
|
||
|
||
### Optional additional copy
|
||
|
||
Use only if the page needs more conversion support:
|
||
|
||
```txt
|
||
Learn by playing.
|
||
Build stories with whimsical characters.
|
||
Practice grammar, usage, and style without worksheets.
|
||
Designed for modular, multi-platform deployment.
|
||
```
|
||
|
||
---
|
||
|
||
## 18. Launch Checklist
|
||
|
||
### Visual
|
||
|
||
```txt
|
||
Logo displays crisply on desktop and mobile.
|
||
Video card scales correctly.
|
||
Background does not overpower text.
|
||
Text remains readable at all breakpoints.
|
||
CTA buttons, if used, are obvious but not visually noisy.
|
||
```
|
||
|
||
### SEO
|
||
|
||
```txt
|
||
Unique title.
|
||
Meta description.
|
||
Canonical URL.
|
||
Open Graph tags.
|
||
Twitter card tags.
|
||
Robots.txt.
|
||
Sitemap.xml.
|
||
Visible/indexable body text.
|
||
Single H1.
|
||
No accidental noindex.
|
||
```
|
||
|
||
### Performance
|
||
|
||
```txt
|
||
Images compressed.
|
||
Video uses poster and preload=metadata.
|
||
No unnecessary JS libraries.
|
||
No large animation library.
|
||
No layout shift.
|
||
Passes Lighthouse performance target.
|
||
```
|
||
|
||
### Accessibility
|
||
|
||
```txt
|
||
Keyboard navigable.
|
||
Visible focus styles.
|
||
Video controls available.
|
||
Captions if voiceover exists.
|
||
Color contrast passes.
|
||
Reduced-motion support.
|
||
No text-only information inside images.
|
||
```
|
||
|
||
### Security
|
||
|
||
```txt
|
||
HTTPS enforced.
|
||
CSP configured.
|
||
Security headers configured.
|
||
No exposed secrets.
|
||
No unnecessary third-party scripts.
|
||
Forms validated server-side if present.
|
||
```
|
||
|
||
---
|
||
|
||
## 19. Recommended MVP Scope
|
||
|
||
For the first version, build:
|
||
|
||
```txt
|
||
Static SvelteKit landing page
|
||
Logo hero
|
||
Self-hosted video with poster
|
||
Main descriptive paragraph
|
||
One CTA: Contact Us or Watch Demo
|
||
SEO metadata
|
||
OG image
|
||
robots.txt
|
||
sitemap.xml
|
||
Basic security headers
|
||
Optimized image/video assets
|
||
```
|
||
|
||
Avoid for MVP:
|
||
|
||
```txt
|
||
CMS
|
||
Animation framework
|
||
User accounts
|
||
Heavy analytics
|
||
YouTube embed
|
||
Complex routing
|
||
Newsletter provider scripts loaded on first paint
|
||
```
|
||
|
||
The best implementation is a prerendered SvelteKit page with the brand assets self-hosted, minimal JavaScript, real HTML text, and a tightly optimized media pipeline.
|