ima2-gen 2.0.15 → 2.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -0
- package/bin/commands/skill.js +336 -17
- package/bin/ima2.js +22 -2
- package/bin/lib/doctor-checks.js +6 -4
- package/config.js +1 -0
- package/docs/CLI.md +25 -3
- package/docs/PROMPT_STUDIO.ko.md +29 -0
- package/docs/PROMPT_STUDIO.md +31 -0
- package/docs/migration/runtime-test-inventory.md +7 -1
- package/lib/agentImageVideoGen.js +8 -0
- package/lib/agentQueueStore.js +36 -10
- package/lib/agentQueueWorker.js +79 -7
- package/lib/agentRuntime.js +2 -0
- package/lib/assetLifecycle.js +40 -8
- package/lib/canvasVersionStore.js +86 -0
- package/lib/cardNewsGenerator.js +37 -3
- package/lib/cardNewsJobStore.js +10 -0
- package/lib/cardNewsManifestStore.js +6 -12
- package/lib/cardNewsPath.js +25 -0
- package/lib/db.js +2 -0
- package/lib/generatePipeline.js +474 -0
- package/lib/generationInputValidation.js +32 -0
- package/lib/grokImageCore.js +18 -1
- package/lib/historyIndex.js +11 -4
- package/lib/historyList.js +3 -0
- package/lib/imageMetadata.js +3 -0
- package/lib/inflight.js +30 -3
- package/lib/multimodePipeline.js +462 -0
- package/lib/nodeGeneration.js +440 -0
- package/lib/nodeValidation.js +23 -0
- package/lib/oauthProxy/generators.js +3 -246
- package/lib/oauthProxy/multimodeGenerators.js +251 -0
- package/lib/routeHelpers.js +9 -2
- package/package.json +2 -2
- package/routes/agent.js +4 -4
- package/routes/canvasVersions.js +21 -1
- package/routes/cardNews.js +2 -1
- package/routes/edit.js +25 -9
- package/routes/events.js +5 -1
- package/routes/generate.js +2 -481
- package/routes/keys.js +31 -39
- package/routes/multimode.js +2 -502
- package/routes/nodes.js +3 -448
- package/routes/video.js +12 -3
- package/routes/videoExtended.js +19 -4
- package/server.js +53 -1
- package/skills/ima2/SKILL.md +204 -0
- package/skills/ima2-front/SKILL.md +611 -0
- package/skills/ima2-front/references/a11y-patterns.md +134 -0
- package/skills/ima2-front/references/aesthetics.md +327 -0
- package/skills/ima2-front/references/anti-slop.md +241 -0
- package/skills/ima2-front/references/asset-requirements.md +431 -0
- package/skills/ima2-front/references/brand-asset-sourcing.md +122 -0
- package/skills/ima2-front/references/color-system.md +132 -0
- package/skills/ima2-front/references/consistency-locks.md +20 -0
- package/skills/ima2-front/references/crud-ui.md +53 -0
- package/skills/ima2-front/references/dropdown-layer.md +110 -0
- package/skills/ima2-front/references/i18n-global.md +104 -0
- package/skills/ima2-front/references/iterative-design.md +90 -0
- package/skills/ima2-front/references/korea-2026.md +174 -0
- package/skills/ima2-front/references/layout-discipline.md +161 -0
- package/skills/ima2-front/references/liquid-glass.md +181 -0
- package/skills/ima2-front/references/logo-sections.md +194 -0
- package/skills/ima2-front/references/mobile-ux.md +144 -0
- package/skills/ima2-front/references/performance-budget.md +106 -0
- package/skills/ima2-front/references/preflight-full.md +58 -0
- package/skills/ima2-front/references/product-density.md +53 -0
- package/skills/ima2-front/references/prototype-variants.md +54 -0
- package/skills/ima2-front/references/reference-capture.md +120 -0
- package/skills/ima2-front/references/responsive-viewport.md +139 -0
- package/skills/ima2-front/references/seo-baseline.md +123 -0
- package/skills/ima2-front/references/soft-3d-asset-gates.md +70 -0
- package/skills/ima2-front/references/stacks/astro.md +204 -0
- package/skills/ima2-front/references/stacks/mobile-native.md +281 -0
- package/skills/ima2-front/references/stacks/nextjs.md +219 -0
- package/skills/ima2-front/references/stacks/react.md +264 -0
- package/skills/ima2-front/references/stacks/svelte.md +235 -0
- package/skills/ima2-front/references/stacks/vanilla.md +226 -0
- package/skills/ima2-front/references/theme-switching.md +82 -0
- package/skills/ima2-front/references/top-bar.md +126 -0
- package/skills/ima2-front/references/typography-wrapping.md +270 -0
- package/skills/ima2-front/references/ux-writing-ko.md +62 -0
- package/skills/ima2-front/references/visual-verification.md +102 -0
- package/skills/ima2-uiux/SKILL.md +477 -0
- package/skills/ima2-uiux/references/anti-slop-judgment.md +39 -0
- package/skills/ima2-uiux/references/color-system.md +80 -0
- package/skills/ima2-uiux/references/design-isms.md +194 -0
- package/skills/ima2-uiux/references/design-read-example.md +33 -0
- package/skills/ima2-uiux/references/design-system-bootstrap.md +133 -0
- package/skills/ima2-uiux/references/favicon-logo.md +355 -0
- package/skills/ima2-uiux/references/form-patterns.md +118 -0
- package/skills/ima2-uiux/references/intent-discovery-ladder.md +86 -0
- package/skills/ima2-uiux/references/korean-design-vocabulary.md +52 -0
- package/skills/ima2-uiux/references/layout-macrostructures.md +54 -0
- package/skills/ima2-uiux/references/logo-trust-sections.md +96 -0
- package/skills/ima2-uiux/references/mobile-native-ux.md +207 -0
- package/skills/ima2-uiux/references/product-personalities.md +118 -0
- package/skills/ima2-uiux/references/responsive-nav.md +66 -0
- package/skills/ima2-uiux/references/typography-line-breaks.md +193 -0
- package/skills/ima2-uiux/references/ux-preflight.md +65 -0
- package/skills/ima2-uiux/references/ux-states.md +197 -0
- package/skills/ima2-uiux/references/visual-hierarchy.md +115 -0
- package/ui/dist/.vite/manifest.json +13 -13
- package/ui/dist/assets/AgentWorkspace-CtYt4SF5.js +3 -0
- package/ui/dist/assets/{CardNewsWorkspace-Cdxn1ohU.js → CardNewsWorkspace-DN5cVqG5.js} +1 -1
- package/ui/dist/assets/GenerationRequestLogPanel-DnmUQdKR.js +1 -0
- package/ui/dist/assets/{NodeCanvas-C67sLboA.js → NodeCanvas-CxpfIBI0.js} +1 -1
- package/ui/dist/assets/PromptBuilderPanel-C2R3ObtR.js +2 -0
- package/ui/dist/assets/{PromptImportDialog-DeQXsEEv.js → PromptImportDialog-BIxz_yEx.js} +2 -2
- package/ui/dist/assets/PromptImportDiscoverySection-BQTlPMME.js +1 -0
- package/ui/dist/assets/PromptImportFolderSection-Ds_Th9O3.js +1 -0
- package/ui/dist/assets/{PromptLibraryPanel-Db3xEPM_.js → PromptLibraryPanel-Rs4l45pV.js} +2 -2
- package/ui/dist/assets/{SettingsWorkspace-BDk_1W-V.js → SettingsWorkspace-p1AZ6uT9.js} +1 -1
- package/ui/dist/assets/index-0-_vgFGs.js +4 -0
- package/ui/dist/assets/index-Dm3pFxV4.js +23 -0
- package/ui/dist/assets/index-J8yDF3Ch.css +1 -0
- package/ui/dist/index.html +2 -2
- package/ui/dist/assets/AgentWorkspace-DAg_7zpY.js +0 -3
- package/ui/dist/assets/GenerationRequestLogPanel-C_qvEUi2.js +0 -1
- package/ui/dist/assets/PromptBuilderPanel-DjvVdAie.js +0 -2
- package/ui/dist/assets/PromptImportDiscoverySection-CrwyUKYI.js +0 -1
- package/ui/dist/assets/PromptImportFolderSection-CToGMqYE.js +0 -1
- package/ui/dist/assets/index-2oG6in1i.css +0 -1
- package/ui/dist/assets/index-CoxMOXAU.js +0 -23
- package/ui/dist/assets/index-p8egnGHk.js +0 -4
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Reference Capture
|
|
2
|
+
|
|
3
|
+
Capture reference sites only to learn structure, ground visual judgment, and
|
|
4
|
+
provide reference material for concept mockups. Captures are analysis inputs,
|
|
5
|
+
not project assets.
|
|
6
|
+
|
|
7
|
+
Use this workflow when a page, component, brand system, or visual interaction
|
|
8
|
+
needs source-grounded study before design synthesis or `ima2 --ref` mockups.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Purpose
|
|
13
|
+
|
|
14
|
+
### Analysis-Only Capture (FE-CAPTURE-01, STRICT)
|
|
15
|
+
|
|
16
|
+
Captured third-party HTML, CSS, images, videos, logos, and font references are
|
|
17
|
+
analysis-only. They may be used to:
|
|
18
|
+
|
|
19
|
+
- study layout structure, density, hierarchy, spacing, and interaction shape
|
|
20
|
+
- compare DOM/component composition against a target pattern
|
|
21
|
+
- ground an `ima2 --ref` concept mockup or style exploration
|
|
22
|
+
- document observed behavior in a devlog unit
|
|
23
|
+
|
|
24
|
+
They must not be copied into shipped source, public assets, production
|
|
25
|
+
bundles, marketing exports, or final deliverables.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Mechanics
|
|
30
|
+
|
|
31
|
+
### Capture Channels (FE-CAPTURE-02, DEFAULT)
|
|
32
|
+
|
|
33
|
+
Use the least invasive public capture method that gives enough evidence.
|
|
34
|
+
|
|
35
|
+
| Channel | Use |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| In-app browser `pageAssets` capability | List and bundle observed page assets from the rendered page |
|
|
38
|
+
| `curl` / `wget` | Fetch public HTML, CSS, JSON, images, or videos needed for analysis |
|
|
39
|
+
| DOM snapshot | Record structure, landmarks, role patterns, component nesting, and text density |
|
|
40
|
+
| Screenshot | Capture visual state, responsive breakpoints, hover/open states, and motion posters |
|
|
41
|
+
|
|
42
|
+
Do not bypass auth, paywalls, robots restrictions, private CDNs, signed URLs,
|
|
43
|
+
or technical access controls.
|
|
44
|
+
|
|
45
|
+
### Storage Location (FE-CAPTURE-03, STRICT)
|
|
46
|
+
|
|
47
|
+
Store captures under the active devlog unit, never under shipped project asset
|
|
48
|
+
directories such as `public/`, `assets/`, `images/`, `src/assets/`, or app
|
|
49
|
+
static folders.
|
|
50
|
+
|
|
51
|
+
Recommended shape: `devlog/<active-unit>/captures/manifest.md` plus one
|
|
52
|
+
folder per source with captured DOM, CSS, screenshots, and notes.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Legal Boundary
|
|
57
|
+
|
|
58
|
+
### Never-Ship Rule (FE-CAPTURE-04, STRICT)
|
|
59
|
+
|
|
60
|
+
Captured third-party assets never ship. This includes copied photographs,
|
|
61
|
+
illustrations, videos, icons, logos, CSS artwork, SVGs, and bundled media.
|
|
62
|
+
|
|
63
|
+
Webfont binaries are never copied. Treat webfonts as license-restricted by
|
|
64
|
+
default even when they are publicly downloadable. You may record the font name,
|
|
65
|
+
CSS stack, metrics observations, and usage notes for analysis.
|
|
66
|
+
|
|
67
|
+
Photography, illustrations, videos, and logos are analysis-only unless they are
|
|
68
|
+
independently re-sourced through shippable channels. Shippable brand assets
|
|
69
|
+
come only from `brand-asset-sourcing.md` channels such as official press kits,
|
|
70
|
+
Simple Icons, SVGL, theSVG, or other explicit licensed libraries.
|
|
71
|
+
|
|
72
|
+
### Mockup Reference Boundary (FE-CAPTURE-05, DEFAULT)
|
|
73
|
+
|
|
74
|
+
Captured material may be passed to `ima2 --ref` to ground composition, density,
|
|
75
|
+
palette, or material exploration. The generated concept mockup remains an
|
|
76
|
+
exploration artifact unless all shipped pixels are recreated or sourced through
|
|
77
|
+
legal build-asset channels.
|
|
78
|
+
|
|
79
|
+
Do not crop a captured logo, photo, illustration, or UI region out of a
|
|
80
|
+
reference and place it into the build.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Provenance Manifest
|
|
85
|
+
|
|
86
|
+
### Manifest Required (FE-CAPTURE-06, STRICT)
|
|
87
|
+
|
|
88
|
+
Every capture set needs a manifest stored next to the captured files, usually
|
|
89
|
+
`captures/manifest.md` or `captures/manifest.json` inside the active devlog
|
|
90
|
+
unit.
|
|
91
|
+
|
|
92
|
+
Each capture record must include:
|
|
93
|
+
|
|
94
|
+
| Field | Required Value |
|
|
95
|
+
| --- | --- |
|
|
96
|
+
| `source_url` | Original page or asset URL |
|
|
97
|
+
| `capture_date` | Date captured, preferably ISO `YYYY-MM-DD` |
|
|
98
|
+
| `license_status` | Known license, or `unknown - assume restricted` |
|
|
99
|
+
| `intended_use` | `analysis` or `mockup-ref` |
|
|
100
|
+
| `storage_path` | Path to the local captured file or folder |
|
|
101
|
+
|
|
102
|
+
Optional fields: viewport, interaction state, tool used, notes, and
|
|
103
|
+
replacement plan for any shippable equivalent.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Ship Gate
|
|
108
|
+
|
|
109
|
+
### Captured Asset Preflight (FE-CAPTURE-07, STRICT)
|
|
110
|
+
|
|
111
|
+
Before shipping, verify that no captured third-party asset appears in the
|
|
112
|
+
shipped build. The same row belongs in `preflight-full.md`:
|
|
113
|
+
|
|
114
|
+
```text
|
|
115
|
+
No captured third-party asset in the shipped build; capture manifest present
|
|
116
|
+
for any reference captures.
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
If a captured reference inspired the final design, document the shippable
|
|
120
|
+
replacement source or confirm the final pixels were recreated from scratch.
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Responsive & Viewport Rules (MANDATORY)
|
|
2
|
+
|
|
3
|
+
Every multi-column layout, every full-height section, every image-heavy page MUST follow these rules. "It works at 1440px" is not responsive.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Canonical Breakpoint Tiers
|
|
8
|
+
|
|
9
|
+
| Tier | Breakpoint | Name | Tailwind | Devices |
|
|
10
|
+
|------|-----------|------|----------|---------|
|
|
11
|
+
| T1 | < 640px | Mobile | default | Phone portrait/landscape |
|
|
12
|
+
| T2 | ≥ 640px | Large Mobile | `sm:` | Landscape phones, small tablets |
|
|
13
|
+
| T3 | ≥ 768px | Tablet | `md:` | iPad portrait, desktop half-screen (1440px split) |
|
|
14
|
+
| T4 | ≥ 1024px | Small Desktop | `lg:` | iPad landscape, laptop, desktop half-screen (1920px split) |
|
|
15
|
+
| T5 | ≥ 1280px | Desktop | `xl:` | Standard desktop monitors |
|
|
16
|
+
| T5+ | ≥ 1536px | Large Desktop | `2xl:` | Ultra-wide, large monitors |
|
|
17
|
+
|
|
18
|
+
Use these tiers consistently. Do not invent ad-hoc `@media` breakpoints. Container query breakpoints are based on container width (not viewport tiers) — custom values like 400px or 900px are fine there.
|
|
19
|
+
|
|
20
|
+
## Page Containment (MANDATORY)
|
|
21
|
+
|
|
22
|
+
Every page layout MUST have a max-width wrapper:
|
|
23
|
+
```css
|
|
24
|
+
max-w-[1400px] mx-auto px-4 sm:px-6 lg:px-8
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Without containment, text lines stretch to 200+ characters on wide monitors — unreadable.
|
|
28
|
+
Full-bleed sections (hero images, color blocks) break out of containment with negative margins or `w-screen`.
|
|
29
|
+
|
|
30
|
+
## Viewport Units
|
|
31
|
+
|
|
32
|
+
- `min-h-[100dvh]` — ALWAYS. Accounts for mobile browser chrome (iOS Safari address bar).
|
|
33
|
+
- `h-screen` / `100vh` — BANNED for full-height sections. These cause layout jump on mobile.
|
|
34
|
+
- `svh` — use for "minimum guaranteed visible height" (rare).
|
|
35
|
+
- `lvh` — use for background sizing where slight overflow is acceptable.
|
|
36
|
+
|
|
37
|
+
## Container Queries (default for components)
|
|
38
|
+
|
|
39
|
+
Prefer `@container` over `@media` for any reusable component. Components should adapt to their parent's width, not the viewport — this is what makes the same component work in a sidebar, modal, full-width layout, AND split-screen.
|
|
40
|
+
|
|
41
|
+
```css
|
|
42
|
+
.card-grid { container-type: inline-size; }
|
|
43
|
+
|
|
44
|
+
@container (min-width: 600px) {
|
|
45
|
+
.card-grid { grid-template-columns: repeat(2, 1fr); }
|
|
46
|
+
}
|
|
47
|
+
@container (min-width: 900px) {
|
|
48
|
+
.card-grid { grid-template-columns: repeat(3, 1fr); }
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Reserve `@media` for page-level layout shifts (sidebar show/hide, nav mode switch, page grid columns).
|
|
53
|
+
|
|
54
|
+
## Split-Screen / Half-Window (the neglected viewport)
|
|
55
|
+
|
|
56
|
+
macOS split-view on a 1440px display gives each app ~640-720px. Windows snap on 1440px gives ~720px. On 1920px displays, each half is ~960px.
|
|
57
|
+
|
|
58
|
+
This range (640-1024px) falls between "mobile collapse" and "full desktop." Most pages break here because rules only exist for < 768px and ≥ 1280px.
|
|
59
|
+
|
|
60
|
+
Rules:
|
|
61
|
+
- At 640-767px (T2): 2-column grids reduce to 1-column. Side-by-side hero stacks. Padding tightens.
|
|
62
|
+
- At 768-1023px (T3): 3-column grids reduce to 2-column. Hero can remain side-by-side if text-heavy. Bento reduces to 2-column.
|
|
63
|
+
- Test at 768px AND 1024px in addition to mobile and desktop widths.
|
|
64
|
+
|
|
65
|
+
## Responsive Spacing Scale
|
|
66
|
+
|
|
67
|
+
Section padding scales with viewport tier:
|
|
68
|
+
|
|
69
|
+
| Element | Mobile (<640px) | Tablet (640-1023px) | Desktop (≥1024px) |
|
|
70
|
+
|---------|-----------------|---------------------|--------------------|
|
|
71
|
+
| Section vertical padding | `py-12` (3rem) | `py-16` (4rem) | `py-20` to `py-24` (5-6rem) |
|
|
72
|
+
| Section horizontal padding | `px-4` (1rem) | `px-6` (1.5rem) | `px-8` (2rem) |
|
|
73
|
+
| Inter-section gap | `gap-12` | `gap-16` | `gap-20` |
|
|
74
|
+
| Card grid gap | `gap-4` | `gap-5` | `gap-6` |
|
|
75
|
+
| Content max-width | `max-w-full` | `max-w-2xl` | `max-w-[1400px]` |
|
|
76
|
+
|
|
77
|
+
## Responsive Images (MANDATORY for image-heavy pages)
|
|
78
|
+
|
|
79
|
+
### srcset / sizes
|
|
80
|
+
Above-fold / LCP images use `loading="eager"` (or omit — eager is the default) + `fetchpriority="high"`. Below-fold images use `loading="lazy"`. Example (above-fold hero):
|
|
81
|
+
```html
|
|
82
|
+
<img
|
|
83
|
+
src="hero-800.webp"
|
|
84
|
+
srcset="hero-400.webp 400w, hero-800.webp 800w, hero-1200.webp 1200w"
|
|
85
|
+
sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 800px"
|
|
86
|
+
alt="..."
|
|
87
|
+
loading="eager"
|
|
88
|
+
fetchpriority="high"
|
|
89
|
+
decoding="async"
|
|
90
|
+
/>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Art Direction (picture element)
|
|
94
|
+
When the image crop must change between viewports (landscape hero → portrait on mobile):
|
|
95
|
+
```html
|
|
96
|
+
<picture>
|
|
97
|
+
<source media="(max-width: 639px)" srcset="hero-portrait.webp" />
|
|
98
|
+
<source media="(max-width: 1023px)" srcset="hero-square.webp" />
|
|
99
|
+
<img src="hero-landscape.webp" alt="..." />
|
|
100
|
+
</picture>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Aspect Ratio
|
|
104
|
+
Lock aspect ratios to prevent layout shift:
|
|
105
|
+
```css
|
|
106
|
+
.hero-image { aspect-ratio: 16/9; object-fit: cover; }
|
|
107
|
+
@media (max-width: 767px) { .hero-image { aspect-ratio: 4/5; } }
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Safe Area / Notch (MANDATORY for mobile)
|
|
111
|
+
|
|
112
|
+
Modern phones have notches, dynamic islands, and home indicators. Content MUST not hide behind them:
|
|
113
|
+
|
|
114
|
+
Apply safe-area insets selectively, not as blanket body padding (top inset on `body` conflicts with fixed navigation bars):
|
|
115
|
+
|
|
116
|
+
```css
|
|
117
|
+
/* Fixed bottom elements (sticky CTA, tab bar) */
|
|
118
|
+
.sticky-bottom {
|
|
119
|
+
padding-bottom: calc(0.75rem + env(safe-area-inset-bottom));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* Horizontal safe area for landscape notch devices */
|
|
123
|
+
.page-wrapper {
|
|
124
|
+
padding-left: env(safe-area-inset-left);
|
|
125
|
+
padding-right: env(safe-area-inset-right);
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Add `viewport-fit=cover` to the meta viewport tag:
|
|
130
|
+
```html
|
|
131
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Nav Height Cap
|
|
135
|
+
|
|
136
|
+
- Desktop nav: 64-72px default, 80px absolute max
|
|
137
|
+
- Mobile nav: 56-64px
|
|
138
|
+
- Nav must not consume >10% of viewport height
|
|
139
|
+
- On scroll, nav can compact to 48px with `transition-all duration-200`
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# SEO, GEO & Social Sharing
|
|
2
|
+
|
|
3
|
+
## Technical SEO
|
|
4
|
+
|
|
5
|
+
### Required Meta Tags
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<html lang="ko">
|
|
9
|
+
<head>
|
|
10
|
+
<meta charset="utf-8">
|
|
11
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
12
|
+
<title>{Page Title} — {Site Name}</title> <!-- ≤60 chars -->
|
|
13
|
+
<meta name="description" content="..."> <!-- ≤160 chars -->
|
|
14
|
+
<link rel="canonical" href="https://..."> <!-- absolute URL -->
|
|
15
|
+
</head>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
- One `<title>` per page, unique across the site
|
|
19
|
+
- Description: complete sentence, not keyword stuffing
|
|
20
|
+
- Canonical URL resolves www/non-www and trailing slash consistently
|
|
21
|
+
- `lang` attribute must match page content language
|
|
22
|
+
|
|
23
|
+
### Heading Hierarchy
|
|
24
|
+
|
|
25
|
+
- `<h1>`: one per page, contains primary keyword naturally
|
|
26
|
+
- `<h2>`: section headings, each a distinct topic
|
|
27
|
+
- `<h3>`: subsections within h2. No skipping (h2 → h4 is invalid)
|
|
28
|
+
- Never use heading tags for visual sizing — use CSS classes
|
|
29
|
+
|
|
30
|
+
### Semantic HTML
|
|
31
|
+
|
|
32
|
+
Use `<header>`, `<main>` (one per page), `<article>`, `<section>`, `<aside>`, `<footer>`, `<nav>`. Every `<img>` needs `alt` text. Every `<a>` needs discernible text. Use `<time datetime="...">` for dates.
|
|
33
|
+
|
|
34
|
+
### Structured Data (JSON-LD)
|
|
35
|
+
|
|
36
|
+
Always JSON-LD in `<head>`, never Microdata or RDFa.
|
|
37
|
+
|
|
38
|
+
| Page Type | Schema | Required Fields |
|
|
39
|
+
|-----------|--------|-----------------|
|
|
40
|
+
| Landing/Home | `WebPage` + `Organization` | name, url, logo, description |
|
|
41
|
+
| Product | `Product` | name, description, offers |
|
|
42
|
+
| Blog post | `BlogPosting` | headline, datePublished, dateModified, author, image |
|
|
43
|
+
| FAQ | `FAQPage` + `Question`/`Answer` | each Q&A pair |
|
|
44
|
+
| Service | `Service` | name, description, provider, areaServed |
|
|
45
|
+
| Breadcrumbs | `BreadcrumbList` | itemListElement with position + name + URL |
|
|
46
|
+
|
|
47
|
+
- Schema MUST match visible page content — mismatched schema is penalized
|
|
48
|
+
- Include `dateModified` on content pages
|
|
49
|
+
- FAQPage schema has the highest AI citation lift
|
|
50
|
+
- Test with Google Rich Results Test before shipping
|
|
51
|
+
|
|
52
|
+
### Robots & Sitemap
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
User-agent: *
|
|
56
|
+
Allow: /
|
|
57
|
+
Sitemap: https://example.com/sitemap.xml
|
|
58
|
+
|
|
59
|
+
User-agent: GPTBot
|
|
60
|
+
Allow: /
|
|
61
|
+
User-agent: ChatGPT-User
|
|
62
|
+
Allow: /
|
|
63
|
+
User-agent: anthropic-ai
|
|
64
|
+
Allow: /
|
|
65
|
+
User-agent: PerplexityBot
|
|
66
|
+
Allow: /
|
|
67
|
+
User-agent: Google-Extended
|
|
68
|
+
Allow: /
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
- XML sitemap with `<lastmod>`, `<changefreq>`, `<priority>`
|
|
72
|
+
- Allow AI crawlers by default — GEO requires it
|
|
73
|
+
|
|
74
|
+
## GEO (Generative Engine Optimization)
|
|
75
|
+
|
|
76
|
+
Optimizing content so AI answer engines (ChatGPT, Perplexity, Gemini, Claude) retrieve and cite your content. GEO is a layer ON TOP of SEO, not a replacement.
|
|
77
|
+
|
|
78
|
+
### Strategies
|
|
79
|
+
|
|
80
|
+
1. **Quotable content** — clear factual statements, TL;DR summaries, data tables an LLM can extract verbatim. Primary value proposition in the first 200 words.
|
|
81
|
+
2. **FAQPage schema** — highest AI citation lift. Use whenever the page addresses common questions.
|
|
82
|
+
3. **Content freshness** — visible "Last updated: YYYY-MM-DD" timestamp.
|
|
83
|
+
4. **Authority signals** — original data, proprietary research, expert commentary.
|
|
84
|
+
5. **Performance** — faster FCP strongly correlates with higher AI citation likelihood.
|
|
85
|
+
6. **AI-generated pages** — always SSR/SSG. Never gate critical text behind client-side JS.
|
|
86
|
+
|
|
87
|
+
## Social Sharing
|
|
88
|
+
|
|
89
|
+
### Open Graph (Required)
|
|
90
|
+
|
|
91
|
+
```html
|
|
92
|
+
<meta property="og:title" content="Page Title"> <!-- ≤60 chars -->
|
|
93
|
+
<meta property="og:description" content="..."> <!-- ≤160 chars -->
|
|
94
|
+
<meta property="og:image" content="https://.../og.png"> <!-- 1200x630px -->
|
|
95
|
+
<meta property="og:url" content="https://...">
|
|
96
|
+
<meta property="og:type" content="website">
|
|
97
|
+
<meta property="og:site_name" content="Site Name">
|
|
98
|
+
<meta property="og:locale" content="ko_KR">
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Twitter Cards
|
|
102
|
+
|
|
103
|
+
```html
|
|
104
|
+
<meta name="twitter:card" content="summary_large_image">
|
|
105
|
+
<meta name="twitter:title" content="Page Title">
|
|
106
|
+
<meta name="twitter:description" content="...">
|
|
107
|
+
<meta name="twitter:image" content="https://.../og.png">
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
- OG image: 1200x630px, PNG or JPG, < 1MB, no text smaller than 24px
|
|
111
|
+
- For dynamic pages, generate OG images via edge function (Vercel OG, Satori)
|
|
112
|
+
- Test with Twitter Card Validator, Facebook Debugger
|
|
113
|
+
|
|
114
|
+
## Pre-flight
|
|
115
|
+
|
|
116
|
+
- [ ] `<title>` unique and ≤ 60 chars
|
|
117
|
+
- [ ] `<meta name="description">` present and ≤ 160 chars
|
|
118
|
+
- [ ] `<link rel="canonical">` with absolute URL
|
|
119
|
+
- [ ] `<html lang="...">` matches content language
|
|
120
|
+
- [ ] JSON-LD structured data matches page type
|
|
121
|
+
- [ ] OG tags present (title, description, image, url)
|
|
122
|
+
- [ ] `<h1>` unique, one per page, no skipped levels
|
|
123
|
+
- [ ] "Last updated" date visible on content pages
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Soft 3D / Character-Like Asset Gates
|
|
2
|
+
|
|
3
|
+
Use this when a design includes soft 3D miniatures, toy-like objects, mascot/character illustrations, chibi proportions, rounded pastel 3D graphics, or tactile product metaphors.
|
|
4
|
+
|
|
5
|
+
## Definition
|
|
6
|
+
|
|
7
|
+
"Cute" in this context means visual assets, not Korean copy:
|
|
8
|
+
|
|
9
|
+
- soft 3D miniature objects
|
|
10
|
+
- toy-like product metaphors
|
|
11
|
+
- character or mascot-like illustrations
|
|
12
|
+
- rounded pastel tactile graphics
|
|
13
|
+
- chibi/miniature proportions
|
|
14
|
+
- finance/education/commerce concepts made into friendly objects
|
|
15
|
+
|
|
16
|
+
It does not mean:
|
|
17
|
+
|
|
18
|
+
- aegyo labels
|
|
19
|
+
- childish error messages
|
|
20
|
+
- excessive exclamation marks
|
|
21
|
+
- fake friendliness in high-trust flows
|
|
22
|
+
|
|
23
|
+
## Domain Gate
|
|
24
|
+
|
|
25
|
+
| Domain | Gate |
|
|
26
|
+
| --- | --- |
|
|
27
|
+
| Kids / education | Allowed when it guides learning |
|
|
28
|
+
| Community / casual commerce | Allowed when local, friendly, and restrained |
|
|
29
|
+
| Consumer onboarding | Allowed when it reduces anxiety |
|
|
30
|
+
| Fintech | Allowed only as premium semantic support, Toss-style; text and trust stay primary |
|
|
31
|
+
| Government / public service | Avoid by default |
|
|
32
|
+
| B2B / admin / ops | Avoid by default |
|
|
33
|
+
| Developer tools | Avoid by default |
|
|
34
|
+
| Auth / security / payment | Avoid unless it clarifies state without reducing trust |
|
|
35
|
+
|
|
36
|
+
## Premium vs Slop
|
|
37
|
+
|
|
38
|
+
Premium:
|
|
39
|
+
|
|
40
|
+
- custom or brand-consistent asset system
|
|
41
|
+
- semantic product metaphor
|
|
42
|
+
- consistent lighting, material, perspective, and palette
|
|
43
|
+
- one core graphic or clear hierarchy
|
|
44
|
+
- subordinate to headline, CTA, and state
|
|
45
|
+
- optimized and performant
|
|
46
|
+
- works across supported themes
|
|
47
|
+
|
|
48
|
+
Slop:
|
|
49
|
+
|
|
50
|
+
- generic public 3D icon pack
|
|
51
|
+
- random cute object unrelated to the page
|
|
52
|
+
- inconsistent lighting/materials
|
|
53
|
+
- low-polish AI output
|
|
54
|
+
- decorative overload
|
|
55
|
+
- asset competes with text or CTA
|
|
56
|
+
- heavy 3D scene with no product value
|
|
57
|
+
|
|
58
|
+
## Toss-Style Exception
|
|
59
|
+
|
|
60
|
+
Soft 3D can work in Korean fintech when it behaves like Toss:
|
|
61
|
+
|
|
62
|
+
- blue/white restrained palette
|
|
63
|
+
- finance-related object metaphors
|
|
64
|
+
- high production value
|
|
65
|
+
- text-first hierarchy
|
|
66
|
+
- simple clean digital style
|
|
67
|
+
- no obstruction of key information
|
|
68
|
+
|
|
69
|
+
Do not copy Toss assets. Extract the rule: premium, semantic, restrained, and brand-consistent.
|
|
70
|
+
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# Astro Stack
|
|
2
|
+
|
|
3
|
+
Last reviewed: 2026-06-16
|
|
4
|
+
Applies to: Astro 5.x
|
|
5
|
+
When to read: Building or modifying Astro projects
|
|
6
|
+
Canonical owner: dev-frontend
|
|
7
|
+
|
|
8
|
+
Read `core/aesthetics.md` + `core/anti-slop.md` first.
|
|
9
|
+
|
|
10
|
+
## 1. Islands Architecture
|
|
11
|
+
|
|
12
|
+
Astro ships zero JavaScript by default. Interactive components are explicit **islands** that hydrate independently:
|
|
13
|
+
|
|
14
|
+
```astro
|
|
15
|
+
---
|
|
16
|
+
// Static by default — no JS shipped
|
|
17
|
+
import Header from '../components/Header.astro';
|
|
18
|
+
import Counter from '../components/Counter.tsx'; // React island
|
|
19
|
+
import Newsletter from '../components/Newsletter.svelte'; // Svelte island
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
<Header />
|
|
23
|
+
|
|
24
|
+
<!-- Interactive islands — each hydrates independently -->
|
|
25
|
+
<Counter client:load />
|
|
26
|
+
<Newsletter client:visible />
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
| Directive | When JS Loads | Use Case |
|
|
30
|
+
|-----------|--------------|----------|
|
|
31
|
+
| `client:load` | Immediately on page load | Above-fold interactive elements (nav, search, auth) |
|
|
32
|
+
| `client:idle` | After page is idle (`requestIdleCallback`) | Below-fold interactive elements, analytics |
|
|
33
|
+
| `client:visible` | When element enters viewport | Comments, newsletter forms, lazy widgets |
|
|
34
|
+
| `client:media` | When media query matches | Mobile-only interactive elements |
|
|
35
|
+
| `client:only="react"` | Immediately, no SSR | Components that cannot SSR (canvas, WebGL, browser APIs) |
|
|
36
|
+
| _(none)_ | Never — static HTML only | Content display, navigation, layout |
|
|
37
|
+
|
|
38
|
+
Rules:
|
|
39
|
+
- Default to no `client:*` directive — components are static HTML unless interaction is required.
|
|
40
|
+
- Use `client:visible` for anything below the fold — saves initial bundle size.
|
|
41
|
+
- Use `client:only` only when SSR genuinely fails (browser APIs, canvas) — it sends no HTML.
|
|
42
|
+
- Every `client:*` directive adds a framework runtime to the page bundle — minimize island count.
|
|
43
|
+
- Astro components (`.astro`) are always static — they cannot be islands. Use React/Svelte/Vue for interactive islands.
|
|
44
|
+
|
|
45
|
+
## 2. Multi-Framework Shell
|
|
46
|
+
|
|
47
|
+
Astro uniquely supports mixing frameworks in one project:
|
|
48
|
+
|
|
49
|
+
| Framework | File Extension | Island Support | When to Use |
|
|
50
|
+
|-----------|---------------|---------------|-------------|
|
|
51
|
+
| React | `.tsx` / `.jsx` | Yes | Existing React component library, complex interactive UI |
|
|
52
|
+
| Svelte | `.svelte` | Yes | Lightweight interactivity, transitions, form handling |
|
|
53
|
+
| Vue | `.vue` | Yes | Existing Vue codebase, directive-heavy UI |
|
|
54
|
+
| Solid | `.tsx` (with Solid plugin) | Yes | Performance-critical islands, fine-grained reactivity |
|
|
55
|
+
| Preact | `.tsx` (with Preact plugin) | Yes | Smaller React-compatible islands |
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
// astro.config.mjs
|
|
59
|
+
import { defineConfig } from 'astro/config';
|
|
60
|
+
import react from '@astrojs/react';
|
|
61
|
+
import svelte from '@astrojs/svelte';
|
|
62
|
+
|
|
63
|
+
export default defineConfig({
|
|
64
|
+
integrations: [
|
|
65
|
+
react({ include: ['**/react/*'] }),
|
|
66
|
+
svelte(),
|
|
67
|
+
],
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Rules:
|
|
72
|
+
- Keep to **one primary framework** per project — multi-framework is for migration or specialized components, not default practice.
|
|
73
|
+
- Organize framework-specific components in separate directories (`components/react/`, `components/svelte/`).
|
|
74
|
+
- Shared state between different framework islands requires a framework-agnostic store (nanostores, signals).
|
|
75
|
+
- Do not pass complex objects as island props — islands serialize props through HTML attributes. Use primitive types or simple objects.
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
// Shared state across frameworks with nanostores
|
|
79
|
+
// src/stores/cart.ts
|
|
80
|
+
import { atom, map } from 'nanostores';
|
|
81
|
+
|
|
82
|
+
export const cartItems = map<Record<string, CartItem>>({});
|
|
83
|
+
export const cartCount = atom(0);
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## 3. Content Collections
|
|
87
|
+
|
|
88
|
+
Type-safe content management for Markdown, MDX, YAML, and JSON:
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
// src/content.config.ts (Astro 5 — file-based content config)
|
|
92
|
+
import { defineCollection, z } from 'astro:content';
|
|
93
|
+
import { glob } from 'astro/loaders';
|
|
94
|
+
|
|
95
|
+
const blog = defineCollection({
|
|
96
|
+
loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/blog' }),
|
|
97
|
+
schema: z.object({
|
|
98
|
+
title: z.string(),
|
|
99
|
+
description: z.string(),
|
|
100
|
+
pubDate: z.coerce.date(),
|
|
101
|
+
tags: z.array(z.string()).default([]),
|
|
102
|
+
draft: z.boolean().default(false),
|
|
103
|
+
}),
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
export const collections = { blog };
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
```astro
|
|
110
|
+
---
|
|
111
|
+
// src/pages/blog/[slug].astro
|
|
112
|
+
import { getCollection, render } from 'astro:content';
|
|
113
|
+
|
|
114
|
+
export async function getStaticPaths() {
|
|
115
|
+
const posts = await getCollection('blog', ({ data }) => !data.draft);
|
|
116
|
+
return posts.map(post => ({
|
|
117
|
+
params: { slug: post.id },
|
|
118
|
+
props: { post },
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const { post } = Astro.props;
|
|
123
|
+
const { Content } = await render(post);
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
<article>
|
|
127
|
+
<h1>{post.data.title}</h1>
|
|
128
|
+
<time>{post.data.pubDate.toLocaleDateString()}</time>
|
|
129
|
+
<Content />
|
|
130
|
+
</article>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Rules:
|
|
134
|
+
- Define schemas for all content collections — untyped content defeats the purpose.
|
|
135
|
+
- Use `z.coerce.date()` for dates — Markdown frontmatter dates are strings.
|
|
136
|
+
- Filter drafts in `getCollection()` calls, not in templates.
|
|
137
|
+
- Use Astro 5's `content.config.ts` (replaces `config.ts` in `src/content/`).
|
|
138
|
+
|
|
139
|
+
## 4. Rendering Modes: SSG / SSR / Hybrid
|
|
140
|
+
|
|
141
|
+
| Mode | Config | When to Use |
|
|
142
|
+
|------|--------|-------------|
|
|
143
|
+
| **SSG** (default) | `output: 'static'` | Blog, docs, marketing — content changes infrequently |
|
|
144
|
+
| **SSR** | `output: 'server'` | Auth-gated, personalized, real-time — every request is dynamic |
|
|
145
|
+
| **Hybrid** | `output: 'static'` + per-page `export const prerender = false` | Mostly static site with a few dynamic pages |
|
|
146
|
+
|
|
147
|
+
```astro
|
|
148
|
+
---
|
|
149
|
+
// src/pages/dashboard.astro — dynamic page in hybrid mode
|
|
150
|
+
export const prerender = false;
|
|
151
|
+
|
|
152
|
+
const user = await getUser(Astro.cookies.get('session'));
|
|
153
|
+
if (!user) return Astro.redirect('/login');
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
<h1>Welcome, {user.name}</h1>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Rules:
|
|
160
|
+
- Default to SSG — ship HTML, not a server.
|
|
161
|
+
- Use hybrid mode before full SSR — mark only dynamic pages with `prerender = false`.
|
|
162
|
+
- SSR requires a deployment adapter (`@astrojs/node`, `@astrojs/vercel`, `@astrojs/cloudflare`).
|
|
163
|
+
- Do not use SSR for content that can be statically generated — it adds latency and server cost.
|
|
164
|
+
- Cache SSR responses at the CDN edge when content is user-independent.
|
|
165
|
+
|
|
166
|
+
### Deployment Adapters
|
|
167
|
+
|
|
168
|
+
| Adapter | Target | Install |
|
|
169
|
+
|---------|--------|---------|
|
|
170
|
+
| `@astrojs/node` | Node.js server (Docker, VPS) | `npx astro add node` |
|
|
171
|
+
| `@astrojs/vercel` | Vercel (edge/serverless) | `npx astro add vercel` |
|
|
172
|
+
| `@astrojs/cloudflare` | Cloudflare Workers/Pages | `npx astro add cloudflare` |
|
|
173
|
+
| `@astrojs/netlify` | Netlify Functions | `npx astro add netlify` |
|
|
174
|
+
| _(none)_ | Static output (default) | No adapter needed for SSG |
|
|
175
|
+
|
|
176
|
+
### Performance Characteristics
|
|
177
|
+
|
|
178
|
+
| Metric | Astro 5 | Next.js 16 | SvelteKit 2 |
|
|
179
|
+
|--------|---------|------------|-------------|
|
|
180
|
+
| Default JS shipped | 0 KB (static pages) | Framework runtime (~80 KB) | ~2 KB (compiled) |
|
|
181
|
+
| Hydration model | Islands (opt-in per component) | Full page (RSC partial) | Full page |
|
|
182
|
+
| Multi-framework | Yes (React + Svelte + Vue) | React only | Svelte only |
|
|
183
|
+
| Content layer | Built-in Collections + Zod | MDX (plugin) | mdsvex (plugin) |
|
|
184
|
+
| Build tool | Vite | Turbopack/Webpack | Vite |
|
|
185
|
+
| Best for | Content-heavy, docs, marketing | Full-stack apps | Interactive apps |
|
|
186
|
+
|
|
187
|
+
## 5. Anti-Patterns
|
|
188
|
+
|
|
189
|
+
| Banned | Symptom | Fix |
|
|
190
|
+
|--------|---------|-----|
|
|
191
|
+
| `client:load` on everything | Full React/Vue/Svelte runtime shipped on every page | Use `client:visible` or `client:idle`; most components need no JS |
|
|
192
|
+
| Multiple frameworks without justification | Bundle bloat — each framework adds its runtime | One primary framework; multi-framework only for migration |
|
|
193
|
+
| Complex objects as island props | Serialization errors, silent data loss | Use primitives or simple objects; fetch data inside the island |
|
|
194
|
+
| SSR for static content | Unnecessary server cost and latency | Use SSG or hybrid mode (§4) |
|
|
195
|
+
| Skipping content collection schemas | Untyped frontmatter, runtime errors on missing fields | Always define Zod schemas for collections (§3) |
|
|
196
|
+
|
|
197
|
+
## Pre-flight
|
|
198
|
+
|
|
199
|
+
- [ ] Default rendering is SSG unless dynamic pages are explicitly marked
|
|
200
|
+
- [ ] Islands use appropriate `client:*` directives — no unnecessary `client:load`
|
|
201
|
+
- [ ] Single primary framework chosen; multi-framework justified if present
|
|
202
|
+
- [ ] Content collections have Zod schemas defined
|
|
203
|
+
- [ ] Island prop types are serialization-safe (no functions, classes, or complex objects)
|
|
204
|
+
- [ ] Shared cross-framework state uses nanostores or equivalent
|