@noobsociety/nsds 0.1.0
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 +220 -0
- package/SKILL.md +18 -0
- package/assets/bg.png +0 -0
- package/assets/bloop.png +0 -0
- package/assets/hero.png +0 -0
- package/assets/lamp.png +0 -0
- package/assets/logo.png +0 -0
- package/assets/mailbox.png +0 -0
- package/assets/plaza.png +0 -0
- package/assets/prickle.png +0 -0
- package/assets/sign.png +0 -0
- package/components/buttons/Button.d.ts +21 -0
- package/components/buttons/Button.js +55 -0
- package/components/buttons/Button.prompt.md +22 -0
- package/components/buttons/buttons.card.html +24 -0
- package/components/cards/FeatureCard.d.ts +18 -0
- package/components/cards/FeatureCard.js +36 -0
- package/components/cards/FeatureCard.prompt.md +17 -0
- package/components/cards/QuestCard.d.ts +16 -0
- package/components/cards/QuestCard.js +27 -0
- package/components/cards/QuestCard.prompt.md +19 -0
- package/components/cards/cards.card.html +54 -0
- package/components/navigation/SectionArrow.d.ts +13 -0
- package/components/navigation/SectionArrow.js +28 -0
- package/components/navigation/navigation.card.html +29 -0
- package/components/primitives.css +407 -0
- package/components/react/index.d.ts +11 -0
- package/components/react/index.js +4 -0
- package/components/shared/styles.js +22 -0
- package/guidelines/brand.card.html +41 -0
- package/guidelines/colors.card.html +43 -0
- package/guidelines/motion.card.html +24 -0
- package/guidelines/pixel-accents.card.html +50 -0
- package/guidelines/radii-shadows.card.html +28 -0
- package/guidelines/semantic-colors.card.html +30 -0
- package/guidelines/spacing.card.html +53 -0
- package/guidelines/sprites.card.html +22 -0
- package/guidelines/type.card.html +24 -0
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/mui-theme/ThemeProvider.tsx +20 -0
- package/mui-theme/examples/FeatureCard.tsx +52 -0
- package/mui-theme/examples/QuestStatusChip.tsx +41 -0
- package/mui-theme/examples/SectionHeader.tsx +44 -0
- package/mui-theme/index.ts +2 -0
- package/mui-theme/preview.dc.html +195 -0
- package/mui-theme/support.js +1513 -0
- package/mui-theme/theme.ts +604 -0
- package/package.json +83 -0
- package/references/noobsociety-monokai.dc.html +360 -0
- package/styles.css +12 -0
- package/support.js +1513 -0
- package/tokens/base.css +46 -0
- package/tokens/colors.css +73 -0
- package/tokens/motion.css +64 -0
- package/tokens/spacing.css +70 -0
- package/tokens/typography.css +43 -0
- package/ui-kits/homepage/index.html +319 -0
package/README.md
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# NoobSociety Design System
|
|
2
|
+
|
|
3
|
+
**NSDS** is the reusable NoobSociety Design System package: design tokens, CSS primitives, React components, MUI theme source, pixel assets, and reference UI kits for building NoobSociety interfaces.
|
|
4
|
+
|
|
5
|
+
The system is built around a simple rule: **Monokai colors are semantic foregrounds, dark surfaces are the world canvas.**
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
Install from npm after publish:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @noobsociety/nsds
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Use a local workspace package before publish:
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@noobsociety/nsds": "file:../design-system"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
Import the full CSS entry when you want tokens, base styles, and shared primitives:
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
import '@noobsociety/nsds/styles.css';
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Use React components with the CSS entry:
|
|
34
|
+
|
|
35
|
+
```jsx
|
|
36
|
+
import '@noobsociety/nsds/styles.css';
|
|
37
|
+
import { Button, FeatureCard, QuestCard, SectionArrow } from '@noobsociety/nsds/react';
|
|
38
|
+
|
|
39
|
+
export function Example() {
|
|
40
|
+
return (
|
|
41
|
+
<Button href="https://noobsociety.com">▶ Enter the world</Button>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Use individual token or asset files when a project only needs part of the system:
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
import '@noobsociety/nsds/tokens/colors.css';
|
|
50
|
+
import logoUrl from '@noobsociety/nsds/assets/logo.png';
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Use the MUI theme in TypeScript-aware app bundlers:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { NSThemeProvider, theme, NS } from '@noobsociety/nsds/mui';
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The MUI entry currently exports source TypeScript. Add a build step before publishing to consumers that require plain JavaScript MUI runtime files.
|
|
60
|
+
|
|
61
|
+
## Package Exports
|
|
62
|
+
|
|
63
|
+
| Export | Purpose |
|
|
64
|
+
|---|---|
|
|
65
|
+
| `@noobsociety/nsds` | Root React component entry |
|
|
66
|
+
| `@noobsociety/nsds/react` | React components |
|
|
67
|
+
| `@noobsociety/nsds/mui` | MUI theme source |
|
|
68
|
+
| `@noobsociety/nsds/styles.css` | Full CSS entry |
|
|
69
|
+
| `@noobsociety/nsds/package.json` | Package metadata |
|
|
70
|
+
| `@noobsociety/nsds/components/primitives.css` | Component primitive classes only |
|
|
71
|
+
| `@noobsociety/nsds/tokens/*` | Individual token CSS files |
|
|
72
|
+
| `@noobsociety/nsds/assets/*` | Pixel assets and brand images |
|
|
73
|
+
| `@noobsociety/nsds/guidelines/*` | Specimen cards |
|
|
74
|
+
| `@noobsociety/nsds/references/*` | Polished `.dc.html` references |
|
|
75
|
+
| `@noobsociety/nsds/ui-kits/*` | Complete UI kits |
|
|
76
|
+
|
|
77
|
+
## Design Model
|
|
78
|
+
|
|
79
|
+
### Monokai Foregrounds
|
|
80
|
+
|
|
81
|
+
Monokai colors are used on top of the canvas: text, icons, borders, buttons, status pills, accents, and interaction states. Each hue has one semantic role. Do not reassign a color to a different role.
|
|
82
|
+
|
|
83
|
+
| Token | Hex | Role |
|
|
84
|
+
|---|---|---|
|
|
85
|
+
| `--ns-ink` | `#f8f8f2` | Primary text |
|
|
86
|
+
| `--ns-ink-faint` | `#75715e` | Muted text, captions, placeholders |
|
|
87
|
+
| `--ns-gold` | `#e6db74` | Primary accent, CTAs, eyebrows, active nav |
|
|
88
|
+
| `--ns-green` | `#a6e22e` | Success, live state, `HOLDS` |
|
|
89
|
+
| `--ns-orange` | `#fd971f` | In progress, active state, `BUILDING` |
|
|
90
|
+
| `--ns-cyan` | `#66d9e8` | Planned, info, links |
|
|
91
|
+
| `--ns-pink` | `#f92672` | Highlight, danger, high-energy accent |
|
|
92
|
+
| `--ns-purple` | `#ae81ff` | Decorative, personal, tertiary accent |
|
|
93
|
+
|
|
94
|
+
### Dark Canvas
|
|
95
|
+
|
|
96
|
+
Dark colors sit underneath the Monokai foregrounds. They define the world canvas, raised surfaces, headers, cards, and overlays.
|
|
97
|
+
|
|
98
|
+
| Token | Hex | Role |
|
|
99
|
+
|---|---|---|
|
|
100
|
+
| `--ns-bg-0` | `#1a1a16` | Deepest surface: footer, sidebar, backdrop |
|
|
101
|
+
| `--ns-bg-1` | `#272822` | Page base |
|
|
102
|
+
| `--ns-bg-2` | `#32332b` | Raised surface, icon slot, input fill |
|
|
103
|
+
| `--ns-glass` | `rgba(30,31,26,.88)` | Card and header glass |
|
|
104
|
+
|
|
105
|
+
The default experience is dark. Do not introduce a light-mode default unless it is intentionally designed as a separate theme.
|
|
106
|
+
|
|
107
|
+
## Content Rules
|
|
108
|
+
|
|
109
|
+
- **Voice:** Direct, honest, playful. Not corporate.
|
|
110
|
+
- **Casing:** Sentence case. Title case only for names and proper nouns.
|
|
111
|
+
- **Length:** Short sentences. One idea per sentence.
|
|
112
|
+
- **Emoji:** Avoid emoji. Use pixel accents such as `✦`, `▶`, `★`, `✓`, and `◌` when useful.
|
|
113
|
+
- **Numbers:** Use numbers only when they are specific and meaningful.
|
|
114
|
+
- **Perspective:** Speak directly. Avoid abstract phrases like "users" and "visitors" when "you" is clearer.
|
|
115
|
+
|
|
116
|
+
## Visual Rules
|
|
117
|
+
|
|
118
|
+
### Typography
|
|
119
|
+
|
|
120
|
+
- `Press Start 2P`: wordmark, buttons, status pills, card labels, section accents, and pixel UI.
|
|
121
|
+
- `Inter`: body copy, navigation, subtitles, paragraphs, and dense information.
|
|
122
|
+
- Pixel text must use generous line height. Keep it short.
|
|
123
|
+
- Body copy should stay readable and calm.
|
|
124
|
+
|
|
125
|
+
### Layout
|
|
126
|
+
|
|
127
|
+
- Base spacing follows a 4px grid.
|
|
128
|
+
- Default container width is `1080px`.
|
|
129
|
+
- Full sections use `min-height: calc(100svh - var(--ns-header-h))`.
|
|
130
|
+
- Responsive baseline: `375x667` portrait and `667x375` landscape.
|
|
131
|
+
|
|
132
|
+
### Cards
|
|
133
|
+
|
|
134
|
+
- Use glass surfaces with `10px` radius.
|
|
135
|
+
- Do not add resting drop shadows.
|
|
136
|
+
- Use hover elevation only: `translateY(-4px)` plus the card hover shadow.
|
|
137
|
+
|
|
138
|
+
### Buttons
|
|
139
|
+
|
|
140
|
+
- Primary `play` buttons use gold fill, dark text, a gold border, and a physical press shadow.
|
|
141
|
+
- `ghost` buttons stay transparent until hover.
|
|
142
|
+
- Buttons use `Press Start 2P`.
|
|
143
|
+
|
|
144
|
+
### Motion
|
|
145
|
+
|
|
146
|
+
- Keep interaction motion fast: `150ms ease-out`.
|
|
147
|
+
- Keep decorative motion subtle.
|
|
148
|
+
- Respect reduced motion; `ns-*` animations are disabled under `prefers-reduced-motion: reduce`.
|
|
149
|
+
|
|
150
|
+
## Component Notes
|
|
151
|
+
|
|
152
|
+
### Button
|
|
153
|
+
|
|
154
|
+
Use for primary and secondary actions.
|
|
155
|
+
|
|
156
|
+
```jsx
|
|
157
|
+
<Button variant="play" href="https://noobsociety.com">▶ Enter the world</Button>
|
|
158
|
+
<Button variant="ghost" href="https://github.com/noobsociety">★ Star on GitHub</Button>
|
|
159
|
+
<Button variant="play" size="sm">▶ Play</Button>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### FeatureCard
|
|
163
|
+
|
|
164
|
+
Use for short feature grids. Render inside a `ul`.
|
|
165
|
+
|
|
166
|
+
```jsx
|
|
167
|
+
<FeatureCard
|
|
168
|
+
icon={<CursorIcon />}
|
|
169
|
+
title="The site is a world"
|
|
170
|
+
body="Pages are maps, links are interactables."
|
|
171
|
+
tag="Spatial"
|
|
172
|
+
/>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### QuestCard
|
|
176
|
+
|
|
177
|
+
Use for gate or roadmap states. Render inside an `ol`.
|
|
178
|
+
|
|
179
|
+
```jsx
|
|
180
|
+
<QuestCard
|
|
181
|
+
gate={3}
|
|
182
|
+
title="Objects"
|
|
183
|
+
body="In-space sections open content."
|
|
184
|
+
status="active"
|
|
185
|
+
/>
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Status mapping:
|
|
189
|
+
|
|
190
|
+
| Status | Label | Color |
|
|
191
|
+
|---|---|---|
|
|
192
|
+
| `done` | `HOLDS` | `--ns-green` |
|
|
193
|
+
| `active` | `BUILDING` | `--ns-orange` |
|
|
194
|
+
| `planned` | `PLANNED` | `--ns-cyan` |
|
|
195
|
+
| `locked` | `LATER` | `--ns-ink-faint` |
|
|
196
|
+
|
|
197
|
+
## File Index
|
|
198
|
+
|
|
199
|
+
| Path | Contents |
|
|
200
|
+
|---|---|
|
|
201
|
+
| `package.json` | Package metadata, exports, peer dependencies |
|
|
202
|
+
| `index.js` / `index.d.ts` | Root React component entry point |
|
|
203
|
+
| `styles.css` | Global CSS entry point |
|
|
204
|
+
| `support.js` | Runtime support for root `.dc.html` references |
|
|
205
|
+
| `tokens/` | Color, typography, spacing, motion, and base CSS tokens |
|
|
206
|
+
| `components/primitives.css` | Shared CSS primitives |
|
|
207
|
+
| `components/react/` | Public React component barrel export |
|
|
208
|
+
| `components/buttons/` | Button component, types, prompt, specimen |
|
|
209
|
+
| `components/cards/` | FeatureCard and QuestCard components, types, prompts, specimens |
|
|
210
|
+
| `components/navigation/` | SectionArrow component, types, specimen |
|
|
211
|
+
| `mui-theme/` | MUI theme source and examples |
|
|
212
|
+
| `assets/` | Logo, sprites, and world imagery |
|
|
213
|
+
| `guidelines/` | Visual specimen cards |
|
|
214
|
+
| `references/` | Polished `.dc.html` references |
|
|
215
|
+
| `ui-kits/` | Complete UI kits |
|
|
216
|
+
| `SKILL.md` | Agent skill definition |
|
|
217
|
+
|
|
218
|
+
## Package Status
|
|
219
|
+
|
|
220
|
+
The current package is ready for local reuse and npm publication as `@noobsociety/nsds@0.1.0`. Before broad public adoption, add a repository URL and choose a license.
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: noobsociety-design
|
|
3
|
+
description: Use this skill to design and implement NoobSociety interfaces with the NSDS package, including design tokens, CSS primitives, React components, MUI theme source, pixel assets, and reference UI kits.
|
|
4
|
+
user-invocable: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Read `README.md` first, then inspect the relevant tokens, components, assets, guidelines, references, or UI kits for the task.
|
|
8
|
+
|
|
9
|
+
If creating visual artifacts such as mockups, slides, or prototypes, use the included assets and produce static HTML the user can open. If working in production code, import the package entry points and follow the documented token and component rules.
|
|
10
|
+
|
|
11
|
+
**Core principles:**
|
|
12
|
+
1. Monokai colors are semantic foregrounds: text, icons, accents, buttons, borders, and status colors.
|
|
13
|
+
2. Dark surfaces are the world canvas: page base, raised surfaces, glass overlays, cards, headers, and footers.
|
|
14
|
+
3. Never reassign a Monokai color to a different semantic role.
|
|
15
|
+
4. The default experience is dark. Do not introduce light mode as the default.
|
|
16
|
+
5. Keep copy direct, short, and playful without becoming corporate.
|
|
17
|
+
|
|
18
|
+
When the user does not specify an output format, choose the most useful one: static HTML for visual artifacts, package imports for production code, or concise design guidance for review and planning.
|
package/assets/bg.png
ADDED
|
Binary file
|
package/assets/bloop.png
ADDED
|
Binary file
|
package/assets/hero.png
ADDED
|
Binary file
|
package/assets/lamp.png
ADDED
|
Binary file
|
package/assets/logo.png
ADDED
|
Binary file
|
|
Binary file
|
package/assets/plaza.png
ADDED
|
Binary file
|
|
Binary file
|
package/assets/sign.png
ADDED
|
Binary file
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @startingPoint section="Components" subtitle="Play and Ghost button variants" viewport="700x180"
|
|
3
|
+
*/
|
|
4
|
+
import type * as React from 'react';
|
|
5
|
+
|
|
6
|
+
export interface ButtonProps {
|
|
7
|
+
/** Visual style */
|
|
8
|
+
variant?: 'play' | 'ghost';
|
|
9
|
+
/** Size */
|
|
10
|
+
size?: 'sm' | 'md' | 'lg';
|
|
11
|
+
/** Render as <a> when provided */
|
|
12
|
+
href?: string;
|
|
13
|
+
onClick?: React.MouseEventHandler<HTMLAnchorElement | HTMLButtonElement>;
|
|
14
|
+
children?: React.ReactNode;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
className?: string;
|
|
17
|
+
style?: React.CSSProperties;
|
|
18
|
+
type?: 'button' | 'submit' | 'reset';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export declare function Button(props: ButtonProps): React.ReactElement;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { cx } from '../shared/styles.js';
|
|
4
|
+
|
|
5
|
+
const VALID_VARIANTS = new Set(['play', 'ghost']);
|
|
6
|
+
const VALID_SIZES = new Set(['sm', 'md', 'lg']);
|
|
7
|
+
|
|
8
|
+
export function Button({
|
|
9
|
+
variant = 'play',
|
|
10
|
+
size = 'md',
|
|
11
|
+
href,
|
|
12
|
+
onClick,
|
|
13
|
+
children,
|
|
14
|
+
disabled = false,
|
|
15
|
+
className,
|
|
16
|
+
type = 'button',
|
|
17
|
+
...props
|
|
18
|
+
}) {
|
|
19
|
+
const resolvedVariant = VALID_VARIANTS.has(variant) ? variant : 'play';
|
|
20
|
+
const resolvedSize = VALID_SIZES.has(size) ? size : 'md';
|
|
21
|
+
const classes = cx(
|
|
22
|
+
'ns-button',
|
|
23
|
+
`ns-button--${resolvedVariant}`,
|
|
24
|
+
`ns-button--${resolvedSize}`,
|
|
25
|
+
className,
|
|
26
|
+
);
|
|
27
|
+
const commonProps = {
|
|
28
|
+
...props,
|
|
29
|
+
className: classes,
|
|
30
|
+
onClick: disabled ? undefined : onClick,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
if (href) {
|
|
34
|
+
return React.createElement(
|
|
35
|
+
'a',
|
|
36
|
+
{
|
|
37
|
+
...commonProps,
|
|
38
|
+
href: disabled ? undefined : href,
|
|
39
|
+
'aria-disabled': disabled || undefined,
|
|
40
|
+
tabIndex: disabled ? -1 : props.tabIndex,
|
|
41
|
+
},
|
|
42
|
+
children,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return React.createElement(
|
|
47
|
+
'button',
|
|
48
|
+
{
|
|
49
|
+
...commonProps,
|
|
50
|
+
type,
|
|
51
|
+
disabled,
|
|
52
|
+
},
|
|
53
|
+
children,
|
|
54
|
+
);
|
|
55
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Use `Button` for primary and secondary actions in NoobSociety interfaces.
|
|
2
|
+
|
|
3
|
+
```jsx
|
|
4
|
+
<Button variant="play" href="https://noobsociety.com">▶ Enter the world</Button>
|
|
5
|
+
<Button variant="ghost" href="https://github.com/noobsociety">★ Star on GitHub</Button>
|
|
6
|
+
<Button variant="play" size="sm">▶ Play</Button>
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
**Variants**
|
|
10
|
+
- `play` — primary CTA. Gold fill, dark text, gold border, physical press shadow.
|
|
11
|
+
- `ghost` — secondary CTA. Transparent surface, gold text, soft border, gold fill on hover.
|
|
12
|
+
|
|
13
|
+
**Sizes**
|
|
14
|
+
- `sm` — compact header actions
|
|
15
|
+
- `md` — default actions
|
|
16
|
+
- `lg` — hero and major CTA sections
|
|
17
|
+
|
|
18
|
+
**Notes**
|
|
19
|
+
- Always uses Press Start 2P — never Inter.
|
|
20
|
+
- Pass `href` to render as `<a>`. Omit for `<button>`.
|
|
21
|
+
- Import `styles.css` so the `ns-button` primitive classes are available.
|
|
22
|
+
- Use a short pixel symbol prefix such as `▶` or `★` when it clarifies the action.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<!-- @dsCard group="Components" viewport="700x200" name="Button" subtitle="Play (primary) and Ghost (secondary) — SVG icons, fluid padding" -->
|
|
2
|
+
<!DOCTYPE html>
|
|
3
|
+
<html>
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<link rel="stylesheet" href="../../styles.css">
|
|
7
|
+
<style>
|
|
8
|
+
body { background: var(--ns-bg-1); padding: 1.75rem 2rem; display: flex; flex-direction: column; gap: 1.5rem; }
|
|
9
|
+
.row { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: center; }
|
|
10
|
+
.label { font-family: var(--ns-font-pixel); font-size: 7px; color: var(--ns-ink-faint); min-width: 3.75rem; }
|
|
11
|
+
</style>
|
|
12
|
+
</head>
|
|
13
|
+
<body>
|
|
14
|
+
<div class="row">
|
|
15
|
+
<span class="label">Play</span>
|
|
16
|
+
<a class="ns-button ns-button--play ns-button--md" href="#"><svg viewBox="0 0 10 10" width="10" height="10" fill="currentColor" aria-hidden="true"><polygon points="1,0.5 9.5,5 1,9.5"/></svg>Enter the world</a>
|
|
17
|
+
<a class="ns-button ns-button--play ns-button--sm" href="#"><svg viewBox="0 0 10 10" width="10" height="10" fill="currentColor" aria-hidden="true"><polygon points="1,0.5 9.5,5 1,9.5"/></svg>Play</a>
|
|
18
|
+
</div>
|
|
19
|
+
<div class="row">
|
|
20
|
+
<span class="label">Ghost</span>
|
|
21
|
+
<a class="ns-button ns-button--ghost ns-button--md" href="#"><svg viewBox="0 0 10 10" width="10" height="10" fill="currentColor" aria-hidden="true"><polygon points="5,0.5 6.2,3.8 9.8,3.8 6.9,5.9 8,9.2 5,7.1 2,9.2 3.1,5.9 0.2,3.8 3.8,3.8"/></svg>Star on GitHub</a>
|
|
22
|
+
</div>
|
|
23
|
+
</body>
|
|
24
|
+
</html>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
|
|
3
|
+
export interface FeatureCardProps {
|
|
4
|
+
/** Pixel-art icon element */
|
|
5
|
+
icon: React.ReactNode;
|
|
6
|
+
/** Card heading — Press Start 2P */
|
|
7
|
+
title: string;
|
|
8
|
+
/** Body copy — Inter 14px */
|
|
9
|
+
body: string;
|
|
10
|
+
/** Small tag label in top-right (e.g. "Spatial", "Live") */
|
|
11
|
+
tag?: string;
|
|
12
|
+
/** Icon color — defaults to gold #e6db74 */
|
|
13
|
+
iconColor?: string;
|
|
14
|
+
className?: string;
|
|
15
|
+
style?: React.CSSProperties;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export declare function FeatureCard(props: FeatureCardProps): React.ReactElement;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { NS, cx, mergeStyles } from '../shared/styles.js';
|
|
4
|
+
|
|
5
|
+
export function FeatureCard({
|
|
6
|
+
icon,
|
|
7
|
+
title,
|
|
8
|
+
body,
|
|
9
|
+
tag,
|
|
10
|
+
iconColor = NS.gold,
|
|
11
|
+
className,
|
|
12
|
+
style,
|
|
13
|
+
...props
|
|
14
|
+
}) {
|
|
15
|
+
return React.createElement('li', {
|
|
16
|
+
...props,
|
|
17
|
+
className: cx('ns-card ns-feature-card', className),
|
|
18
|
+
style: mergeStyles({ '--ns-feature-accent': iconColor }, style),
|
|
19
|
+
},
|
|
20
|
+
React.createElement('span', {
|
|
21
|
+
className: 'ns-icon-slot ns-feature-card__icon',
|
|
22
|
+
'aria-hidden': true,
|
|
23
|
+
}, icon),
|
|
24
|
+
React.createElement('div', null,
|
|
25
|
+
React.createElement('h3', {
|
|
26
|
+
className: 'ns-feature-card__title',
|
|
27
|
+
}, title),
|
|
28
|
+
React.createElement('p', {
|
|
29
|
+
className: 'ns-feature-card__body',
|
|
30
|
+
}, body),
|
|
31
|
+
),
|
|
32
|
+
tag && React.createElement('span', {
|
|
33
|
+
className: 'ns-tag ns-feature-card__tag',
|
|
34
|
+
}, tag),
|
|
35
|
+
);
|
|
36
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Use `FeatureCard` for short feature grids and value propositions. Render cards inside a `ul`.
|
|
2
|
+
|
|
3
|
+
```jsx
|
|
4
|
+
<ul style={{ display:'grid', gridTemplateColumns:'repeat(4,1fr)', gap:14, listStyle:'none', margin:0, padding:0 }}>
|
|
5
|
+
<FeatureCard icon={<CursorIcon/>} title="The site is a world" body="Pages are maps, links are interactables." tag="Spatial" />
|
|
6
|
+
<FeatureCard icon={<BoltIcon/>} title="One typed bridge" body="A map object in Phaser fires the matching React overlay." tag="Live" iconColor="var(--ns-pink)" />
|
|
7
|
+
<FeatureCard icon={<BubbleIcon/>} title="Sprite-forward" body="Clear silhouettes, readable at a glance." tag="Personal" iconColor="var(--ns-purple)" />
|
|
8
|
+
<FeatureCard icon={<BookIcon/>} title="Built in the open" body="CI on every push. Cloudflare Pages deploy." tag="Open" iconColor="var(--ns-cyan)" />
|
|
9
|
+
</ul>
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
**Notes**
|
|
13
|
+
- Keep titles short. Pixel headings lose clarity when they wrap too often.
|
|
14
|
+
- `iconColor` should use a semantic Monokai token: gold by default, or pink, purple, or cyan when the meaning fits.
|
|
15
|
+
- Import `styles.css` so the `ns-card`, `ns-feature-card`, and `ns-tag` classes are available.
|
|
16
|
+
- Keep `tag` to one short word.
|
|
17
|
+
- Hover: `translateY(-4px)` + gold border glow.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
|
|
3
|
+
export interface QuestCardProps {
|
|
4
|
+
/** Gate number shown in the title */
|
|
5
|
+
gate: number;
|
|
6
|
+
/** Short gate name (e.g. "Space", "Movement") */
|
|
7
|
+
title: string;
|
|
8
|
+
/** One-sentence description */
|
|
9
|
+
body: string;
|
|
10
|
+
/** Controls border color, bg tint, icon, and pill label */
|
|
11
|
+
status?: 'done' | 'active' | 'planned' | 'locked';
|
|
12
|
+
className?: string;
|
|
13
|
+
style?: React.CSSProperties;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export declare function QuestCard(props: QuestCardProps): React.ReactElement;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { cx, questStatus } from '../shared/styles.js';
|
|
4
|
+
|
|
5
|
+
export function QuestCard({ gate, title, body, status = 'locked', className, ...props }) {
|
|
6
|
+
const s = questStatus[status] || questStatus.locked;
|
|
7
|
+
return React.createElement('li', {
|
|
8
|
+
...props,
|
|
9
|
+
className: cx('ns-quest-card', s.className, className),
|
|
10
|
+
},
|
|
11
|
+
React.createElement('span', {
|
|
12
|
+
className: 'ns-quest-card__icon',
|
|
13
|
+
'aria-hidden': true,
|
|
14
|
+
}, s.icon),
|
|
15
|
+
React.createElement('div', { className: 'ns-quest-card__body' },
|
|
16
|
+
React.createElement('p', {
|
|
17
|
+
className: 'ns-quest-card__title',
|
|
18
|
+
}, `Gate ${gate} · ${title}`),
|
|
19
|
+
React.createElement('p', {
|
|
20
|
+
className: 'ns-quest-card__desc',
|
|
21
|
+
}, body),
|
|
22
|
+
React.createElement('span', {
|
|
23
|
+
className: 'ns-status-pill',
|
|
24
|
+
}, s.label),
|
|
25
|
+
),
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Use `QuestCard` for roadmap gates, progress checkpoints, and locked future work. Render cards inside an `ol`.
|
|
2
|
+
|
|
3
|
+
```jsx
|
|
4
|
+
<ol style={{ display:'grid', gridTemplateColumns:'repeat(3,1fr)', gap:11, listStyle:'none', margin:0, padding:0 }}>
|
|
5
|
+
<QuestCard gate={1} title="Space" body="Walkable area exists." status="done" />
|
|
6
|
+
<QuestCard gate={2} title="Movement" body="Movement feels right." status="done" />
|
|
7
|
+
<QuestCard gate={3} title="Objects" body="In-space sections open content." status="active" />
|
|
8
|
+
<QuestCard gate={6} title="Identity" body="Space and character read as one." status="planned" />
|
|
9
|
+
<QuestCard gate={8} title="Combat" body="Unlocks after single-player loop." status="locked" />
|
|
10
|
+
</ol>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
**Status mapping**
|
|
14
|
+
- `done` → `HOLDS`, green `#a6e22e`
|
|
15
|
+
- `active` → `BUILDING`, orange `#fd971f`
|
|
16
|
+
- `planned` → `PLANNED`, cyan `#66d9e8`
|
|
17
|
+
- `locked` → `LATER`, faint `#75715e`, reduced opacity
|
|
18
|
+
|
|
19
|
+
Import `styles.css` so the `ns-quest-card` and `ns-status-pill` classes are available.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<!-- @dsCard group="Components" viewport="700x380" name="Cards" subtitle="FeatureCard (semantic colors) and QuestCard (status system)" -->
|
|
2
|
+
<!DOCTYPE html>
|
|
3
|
+
<html>
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<link rel="stylesheet" href="../../styles.css">
|
|
7
|
+
<style>
|
|
8
|
+
body { background: var(--ns-bg-1); padding: 1.5rem 1.75rem; display: flex; flex-direction: column; gap: 1.25rem; }
|
|
9
|
+
.label { font-family: var(--ns-font-pixel); font-size: 7px; color: var(--ns-ink-faint); margin: 0 0 0.625rem; }
|
|
10
|
+
.grid-4 { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: 0.875rem; list-style: none; margin: 0; padding: 0; }
|
|
11
|
+
.grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 0.875rem; list-style: none; margin: 0; padding: 0; }
|
|
12
|
+
</style>
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<p class="label">Feature cards — icon colors are Monokai semantic</p>
|
|
16
|
+
<ul class="grid-4">
|
|
17
|
+
<li class="ns-card ns-feature-card">
|
|
18
|
+
<div class="ns-icon-slot ns-feature-card__icon"><svg viewBox="0 0 24 24" width="26" height="26" fill="currentColor" aria-hidden="true"><path d="M5 2.6 L5 18.6 L9.2 14.7 L12 20.8 L14.4 19.6 L11.6 13.7 L17.4 13.7 Z"/></svg></div>
|
|
19
|
+
<div><p class="ns-feature-card__title">The site is a world</p><p class="ns-feature-card__body">Pages are maps, links are interactables.</p></div>
|
|
20
|
+
<span class="ns-tag ns-feature-card__tag">Spatial</span>
|
|
21
|
+
</li>
|
|
22
|
+
<li class="ns-card ns-feature-card" style="--ns-feature-accent: var(--ns-pink)">
|
|
23
|
+
<div class="ns-icon-slot ns-feature-card__icon"><svg viewBox="0 0 24 24" width="26" height="26" fill="currentColor" aria-hidden="true"><path d="M13 2.5 L5 13.6 H11 L10.2 21.5 L19 9.4 H12.4 Z"/></svg></div>
|
|
24
|
+
<div><p class="ns-feature-card__title">One typed bridge</p><p class="ns-feature-card__body">Phaser fires the matching React overlay.</p></div>
|
|
25
|
+
<span class="ns-tag ns-feature-card__tag">Live</span>
|
|
26
|
+
</li>
|
|
27
|
+
<li class="ns-card ns-feature-card" style="--ns-feature-accent: var(--ns-purple)">
|
|
28
|
+
<div class="ns-icon-slot ns-feature-card__icon"><svg viewBox="0 0 24 24" width="26" height="26" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><path d="M12 3.5 C6.9 3.5 3 7.1 3 11.7 C3 15.1 5.5 17.2 8.3 17.2 C9.9 17.2 10.4 16 11.7 16 C12.8 16 13.1 17.3 14.7 17.3 C18 17.3 21 14.7 21 11.1 C21 6.8 17 3.5 12 3.5 Z" stroke-linejoin="round"/><circle cx="8" cy="9" r="1.1" fill="currentColor" stroke="none"/><circle cx="12" cy="7.4" r="1.1" fill="currentColor" stroke="none"/><circle cx="16" cy="9" r="1.1" fill="currentColor" stroke="none"/></svg></div>
|
|
29
|
+
<div><p class="ns-feature-card__title">Sprite-forward</p><p class="ns-feature-card__body">Clear silhouettes, readable at a glance.</p></div>
|
|
30
|
+
<span class="ns-tag ns-feature-card__tag">Personal</span>
|
|
31
|
+
</li>
|
|
32
|
+
<li class="ns-card ns-feature-card" style="--ns-feature-accent: var(--ns-cyan)">
|
|
33
|
+
<div class="ns-icon-slot ns-feature-card__icon"><svg viewBox="0 0 24 24" width="26" height="26" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round" aria-hidden="true"><path d="M12 6.5 C9.5 4.9 6 4.6 3.6 5.5 V18.7 C6 17.8 9.5 18.1 12 19.8 C14.5 18.1 18 17.8 20.4 18.7 V5.5 C18 4.6 14.5 4.9 12 6.5 Z"/><path d="M12 6.5 V19.8"/></svg></div>
|
|
34
|
+
<div><p class="ns-feature-card__title">Built in the open</p><p class="ns-feature-card__body">CI on every push. Cloudflare Pages deploy.</p></div>
|
|
35
|
+
<span class="ns-tag ns-feature-card__tag">Open</span>
|
|
36
|
+
</li>
|
|
37
|
+
</ul>
|
|
38
|
+
<p class="label">Quest cards — status → Monokai color</p>
|
|
39
|
+
<ul class="grid-3">
|
|
40
|
+
<li class="ns-quest-card ns-quest-card--done">
|
|
41
|
+
<span class="ns-quest-card__icon" aria-hidden="true">✓</span>
|
|
42
|
+
<div class="ns-quest-card__body"><p class="ns-quest-card__title">Gate 1 · Space</p><p class="ns-quest-card__desc">Walkable area exists.</p><span class="ns-status-pill">HOLDS</span></div>
|
|
43
|
+
</li>
|
|
44
|
+
<li class="ns-quest-card ns-quest-card--active">
|
|
45
|
+
<span class="ns-quest-card__icon" aria-hidden="true"><svg viewBox="0 0 10 10" width="8" height="8" fill="currentColor"><polygon points="1,0.5 9.5,5 1,9.5"/></svg></span>
|
|
46
|
+
<div class="ns-quest-card__body"><p class="ns-quest-card__title">Gate 3 · Objects</p><p class="ns-quest-card__desc">In-space sections open content.</p><span class="ns-status-pill">BUILDING</span></div>
|
|
47
|
+
</li>
|
|
48
|
+
<li class="ns-quest-card ns-quest-card--planned">
|
|
49
|
+
<span class="ns-quest-card__icon" aria-hidden="true">◌</span>
|
|
50
|
+
<div class="ns-quest-card__body"><p class="ns-quest-card__title">Gate 6 · Identity</p><p class="ns-quest-card__desc">Space and character read as one.</p><span class="ns-status-pill">PLANNED</span></div>
|
|
51
|
+
</li>
|
|
52
|
+
</ul>
|
|
53
|
+
</body>
|
|
54
|
+
</html>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type * as React from 'react';
|
|
2
|
+
|
|
3
|
+
export interface SectionArrowProps {
|
|
4
|
+
/** href of the next section (e.g. "#why") */
|
|
5
|
+
href: string;
|
|
6
|
+
/** Accessible label for screen readers */
|
|
7
|
+
label: string;
|
|
8
|
+
children?: React.ReactNode;
|
|
9
|
+
className?: string;
|
|
10
|
+
style?: React.CSSProperties;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export declare function SectionArrow(props: SectionArrowProps): React.ReactElement;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { cx } from '../shared/styles.js';
|
|
4
|
+
|
|
5
|
+
function ChevronDownIcon() {
|
|
6
|
+
return React.createElement('svg', {
|
|
7
|
+
viewBox: '0 0 12 8',
|
|
8
|
+
width: 12,
|
|
9
|
+
height: 12,
|
|
10
|
+
'aria-hidden': true,
|
|
11
|
+
fill: 'none',
|
|
12
|
+
stroke: 'currentColor',
|
|
13
|
+
strokeWidth: 2,
|
|
14
|
+
strokeLinecap: 'round',
|
|
15
|
+
strokeLinejoin: 'round',
|
|
16
|
+
},
|
|
17
|
+
React.createElement('polyline', { points: '1,1.5 6,6.5 11,1.5' }),
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function SectionArrow({ href, label, className, children, ...props }) {
|
|
22
|
+
return React.createElement('a', {
|
|
23
|
+
...props,
|
|
24
|
+
href,
|
|
25
|
+
'aria-label': label,
|
|
26
|
+
className: cx('ns-section-arrow', className),
|
|
27
|
+
}, children || React.createElement(ChevronDownIcon));
|
|
28
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<!-- @dsCard group="Components" viewport="700x120" name="Navigation" subtitle="SiteNav header with scroll-spy + SVG section arrow" -->
|
|
2
|
+
<!DOCTYPE html>
|
|
3
|
+
<html>
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<link rel="stylesheet" href="../../styles.css">
|
|
7
|
+
<style>
|
|
8
|
+
body { background: var(--ns-bg-1); padding: 0; display: flex; flex-direction: column; }
|
|
9
|
+
.arrow-demo { position:relative; height:3.5rem; background:rgba(30,31,26,.3); }
|
|
10
|
+
.arrow-demo .ns-section-arrow { bottom:0.75rem; }
|
|
11
|
+
.nav-play { margin-left:2rem; }
|
|
12
|
+
</style>
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<nav class="ns-site-nav">
|
|
16
|
+
<a class="ns-brand" href="#"><img src="../../assets/logo.png" alt=""><span class="ns-brand__text">Noob<b class="ns-brand__accent">Society</b></span></a>
|
|
17
|
+
<ul class="ns-nav-links">
|
|
18
|
+
<li><a href="#">Why</a></li>
|
|
19
|
+
<li><a href="#" aria-current="page">World</a></li>
|
|
20
|
+
<li><a href="#">Roadmap</a></li>
|
|
21
|
+
<li><a href="#">Devblog</a></li>
|
|
22
|
+
</ul>
|
|
23
|
+
<a class="ns-button ns-button--play ns-button--sm nav-play" href="#"><svg viewBox="0 0 10 10" width="10" height="10" fill="currentColor" aria-hidden="true"><polygon points="1,0.5 9.5,5 1,9.5"/></svg>Play</a>
|
|
24
|
+
</nav>
|
|
25
|
+
<div class="arrow-demo">
|
|
26
|
+
<a class="ns-section-arrow" href="#" aria-label="Go to next section"><svg viewBox="0 0 12 8" width="12" height="12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="1,1.5 6,6.5 11,1.5"/></svg></a>
|
|
27
|
+
</div>
|
|
28
|
+
</body>
|
|
29
|
+
</html>
|