justskill-design 0.0.1 → 3.2.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.en.md +235 -0
- package/README.md +184 -11
- package/SKILL.md +435 -0
- package/canvas/app.mjs +2870 -0
- package/canvas/groups.mjs +204 -0
- package/canvas/index.html +141 -0
- package/canvas/styles.css +1032 -0
- package/canvas/tree.mjs +249 -0
- package/cordis.patch.yml +8 -0
- package/design.mjs +172 -0
- package/docs/dsh-workbench.png +0 -0
- package/dsh/client.js +864 -0
- package/dsh/index.js +354 -0
- package/dsh/scan.js +139 -0
- package/dsh/skill.js +41 -0
- package/lib/base-css.mjs +92 -0
- package/lib/detect.mjs +123 -0
- package/lib/diagnostics.mjs +382 -0
- package/lib/export-html.mjs +309 -0
- package/lib/export-svg.mjs +111 -0
- package/lib/fragment.mjs +702 -0
- package/lib/geometry.mjs +827 -0
- package/lib/icons.mjs +106 -0
- package/lib/levenshtein.mjs +133 -0
- package/lib/node/cli.mjs +387 -0
- package/lib/node/export-svg.mjs +75 -0
- package/lib/node/fs.mjs +309 -0
- package/lib/node/op-json.mjs +75 -0
- package/lib/node/raster-run.mjs +115 -0
- package/lib/node/server.mjs +1264 -0
- package/lib/node/static.mjs +206 -0
- package/lib/node/verbs/add.mjs +220 -0
- package/lib/node/verbs/export.mjs +161 -0
- package/lib/node/verbs/format.mjs +106 -0
- package/lib/node/verbs/import.mjs +126 -0
- package/lib/node/verbs/ls.mjs +98 -0
- package/lib/node/verbs/migrate.mjs +236 -0
- package/lib/node/verbs/move.mjs +76 -0
- package/lib/node/verbs/new.mjs +284 -0
- package/lib/node/verbs/remove.mjs +41 -0
- package/lib/node/verbs/rename.mjs +87 -0
- package/lib/node/verbs/serve.mjs +164 -0
- package/lib/node/verbs/set.mjs +150 -0
- package/lib/node/verbs/show.mjs +122 -0
- package/lib/node/verbs/tokens.mjs +167 -0
- package/lib/node/verbs/validate.mjs +130 -0
- package/lib/node/write-verbs.mjs +215 -0
- package/lib/normalize.mjs +288 -0
- package/lib/ops.mjs +2063 -0
- package/lib/parse.mjs +997 -0
- package/lib/raster.mjs +186 -0
- package/lib/readers/pen.mjs +1684 -0
- package/lib/receipt.mjs +203 -0
- package/lib/render.mjs +503 -0
- package/lib/serialize.mjs +441 -0
- package/lib/spans.mjs +177 -0
- package/lib/svg-path.mjs +483 -0
- package/lib/table.mjs +1047 -0
- package/lib/tokens.mjs +295 -0
- package/lib/validate.mjs +929 -0
- package/package.json +68 -6
- package/references/cookbook.md +156 -0
- package/references/images.md +171 -0
- package/references/product-flow.md +408 -0
- package/references/schema.md +90 -0
- package/references/styling.md +181 -0
- package/scripts/install.mjs +95 -0
package/package.json
CHANGED
|
@@ -1,10 +1,72 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "justskill-design",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
3
|
+
"version": "3.2.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "Design web pages as a validated HTML file with inline CSS. Agent edits by CLI, human edits on a local canvas, both write the same file. Also ships a DeepSeek Harness plugin.",
|
|
5
7
|
"license": "MIT",
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
"main": "./dsh/index.js",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./dsh/index.js",
|
|
11
|
+
"./client": "./dsh/client.js",
|
|
12
|
+
"./design.mjs": "./design.mjs",
|
|
13
|
+
"./package.json": "./package.json"
|
|
14
|
+
},
|
|
15
|
+
"bin": {
|
|
16
|
+
"justskill": "design.mjs"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"SKILL.md",
|
|
20
|
+
"design.mjs",
|
|
21
|
+
"lib",
|
|
22
|
+
"canvas",
|
|
23
|
+
"references",
|
|
24
|
+
"scripts/install.mjs",
|
|
25
|
+
"dsh",
|
|
26
|
+
"cordis.patch.yml",
|
|
27
|
+
"README.md",
|
|
28
|
+
"LICENSE",
|
|
29
|
+
"README.en.md",
|
|
30
|
+
"docs/dsh-workbench.png"
|
|
31
|
+
],
|
|
32
|
+
"dsh": {
|
|
33
|
+
"bundle": {
|
|
34
|
+
"patch": "./cordis.patch.yml"
|
|
35
|
+
},
|
|
36
|
+
"client": {
|
|
37
|
+
"platform": "web"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"keywords": [
|
|
41
|
+
"justskill",
|
|
42
|
+
"design",
|
|
43
|
+
"html",
|
|
44
|
+
"css",
|
|
45
|
+
"canvas",
|
|
46
|
+
"agent-skills",
|
|
47
|
+
"claude-code",
|
|
48
|
+
"dsh",
|
|
49
|
+
"dsh-plugin",
|
|
50
|
+
"deepseek-harness",
|
|
51
|
+
"skill"
|
|
52
|
+
],
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=18",
|
|
55
|
+
"dsh": ">=0.2.1-rc.3 <0.3.0-0"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"test": "node --test",
|
|
59
|
+
"references": "node scripts/gen-references.mjs",
|
|
60
|
+
"references:check": "node scripts/gen-references.mjs --check",
|
|
61
|
+
"images:check": "node scripts/check-images.mjs",
|
|
62
|
+
"install:skill": "node scripts/install.mjs"
|
|
63
|
+
},
|
|
64
|
+
"repository": {
|
|
65
|
+
"type": "git",
|
|
66
|
+
"url": "git+https://github.com/justskill-ai/justskill-design.git"
|
|
67
|
+
},
|
|
68
|
+
"homepage": "https://github.com/justskill-ai/justskill-design#readme",
|
|
69
|
+
"bugs": {
|
|
70
|
+
"url": "https://github.com/justskill-ai/justskill-design/issues"
|
|
71
|
+
}
|
|
10
72
|
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Cookbook
|
|
2
|
+
|
|
3
|
+
<!-- Generated by scripts/gen-references.mjs from lib/table.mjs. Do not edit. -->
|
|
4
|
+
|
|
5
|
+
The patterns that come up on every page, written the way this format wants them.
|
|
6
|
+
|
|
7
|
+
## Page shell
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<section data-id="home" data-type="page" data-name="Home" data-canvas="0,0" style="width:390px;height:844px">
|
|
11
|
+
<div data-id="home__root" data-type="frame" style="display:flex;flex-direction:column;width:100%;height:100%;background-color:var(--color-bg)">
|
|
12
|
+
</div>
|
|
13
|
+
</section>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The page owns its own size. The root fills it.
|
|
17
|
+
|
|
18
|
+
## A vertical stack with spacing
|
|
19
|
+
|
|
20
|
+
```html
|
|
21
|
+
<div data-id="home__list" data-type="frame" style="display:flex;flex-direction:column;gap:12px;padding:24px">
|
|
22
|
+
</div>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`gap` is the whole spacing system. There is no `margin`.
|
|
26
|
+
|
|
27
|
+
## A row that pushes its ends apart
|
|
28
|
+
|
|
29
|
+
```html
|
|
30
|
+
<div data-id="home__bar" data-type="frame" style="display:flex;align-items:center;justify-content:space-between;height:48px;padding:0 16px;background-color:#ffffff">
|
|
31
|
+
</div>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Two children that split the width
|
|
35
|
+
|
|
36
|
+
```html
|
|
37
|
+
<div data-id="home__split" data-type="frame" style="display:flex;flex-direction:row;gap:8px">
|
|
38
|
+
<div data-id="home__left" data-type="frame" style="flex:1 1 0%;min-width:0"></div>
|
|
39
|
+
<div data-id="home__right" data-type="frame" style="flex:1 1 0%;min-width:0"></div>
|
|
40
|
+
</div>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`flex:1 1 0%` plus `min-width:0` is the one spelled way to fill a row. Without
|
|
44
|
+
`min-width:0`, a long word pushes the child past its share.
|
|
45
|
+
|
|
46
|
+
## A card
|
|
47
|
+
|
|
48
|
+
```html
|
|
49
|
+
<div data-id="home__card" data-type="frame" style="display:flex;flex-direction:column;gap:8px;padding:16px;background-color:#ffffff;border:1px solid #e5e7eb;border-radius:12px;box-shadow:0 1px 2px #00000014">
|
|
50
|
+
</div>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## A tilted card
|
|
54
|
+
|
|
55
|
+
```html
|
|
56
|
+
<div data-id="home__card" data-type="frame" style="transform:rotate(-1.5deg);display:flex;flex-direction:column;gap:8px;padding:16px;background-color:#ffffff;border-radius:16px;box-shadow:0 1px 2px #0000000a, 0 16px 34px -12px #00000014"></div>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`rotate()` turns the element about its own centre and changes no layout: its
|
|
60
|
+
neighbours stay put, and the canvas drags and resizes it along its turned
|
|
61
|
+
axes. `translate()` and `scale()` are refused — they are `left`/`top` and
|
|
62
|
+
`width`/`height` written a second time. A page cannot be rotated; tilt the
|
|
63
|
+
cards on it.
|
|
64
|
+
|
|
65
|
+
## Text sizes
|
|
66
|
+
|
|
67
|
+
| Role | Style |
|
|
68
|
+
|---|---|
|
|
69
|
+
| Display | `font-size:44px;font-weight:700;line-height:1.1` |
|
|
70
|
+
| Title | `font-size:24px;font-weight:600;line-height:1.25` |
|
|
71
|
+
| Body | `font-size:16px;font-weight:400;line-height:1.5` |
|
|
72
|
+
| Label | `font-size:14px;font-weight:500;line-height:1.4` |
|
|
73
|
+
| Caption | `font-size:12px;font-weight:400;line-height:1.4;color:#6b7280` |
|
|
74
|
+
|
|
75
|
+
## A pill
|
|
76
|
+
|
|
77
|
+
```html
|
|
78
|
+
<p data-id="home__tag" data-type="text" style="font-size:12px;font-weight:500;padding:4px 10px;background-color:#f3f4f6;border-radius:9999px;color:#374151">New</p>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`border-radius:9999px` is the pill. A circle is `border-radius:50%` on a square box.
|
|
82
|
+
|
|
83
|
+
## An image that fills its box
|
|
84
|
+
|
|
85
|
+
```html
|
|
86
|
+
<img data-id="home__photo" data-type="image" src="photo.jpg" alt="A room" style="width:100%;height:200px;object-fit:cover;border-radius:12px">
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`alt` is required. `alt=""` marks a decorative image, and that is different from
|
|
90
|
+
omitting it.
|
|
91
|
+
|
|
92
|
+
## A photo when the user gave none
|
|
93
|
+
|
|
94
|
+
Take the `src` from `references/images.md`, and write its `alt` and credit with it:
|
|
95
|
+
|
|
96
|
+
```html
|
|
97
|
+
<img data-id="home__photo" data-type="image" src="https://images.unsplash.com/photo-1543988884-c01cfa7b41c2?w=1080&q=80&fm=jpg" alt="Turquoise water meeting a white sand beach" data-credit="Photo by Harry Holder on Unsplash" style="width:100%;height:220px;object-fit:cover;border-radius:12px">
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`data-credit` names the photographer. It never renders, and the Licence does not
|
|
101
|
+
require it: keeping it costs one attribute and makes the source of a photo findable
|
|
102
|
+
later.
|
|
103
|
+
|
|
104
|
+
## A background image
|
|
105
|
+
|
|
106
|
+
```html
|
|
107
|
+
<div data-id="home__hero" data-type="frame" style="height:240px;background-image:url("hero.jpg");background-size:cover;background-position:center"></div>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## A gradient scrim
|
|
111
|
+
|
|
112
|
+
```html
|
|
113
|
+
<div data-id="home__scrim" data-type="frame" style="height:120px;background-image:linear-gradient(180deg,#ffffff00,#00000099)"></div>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
A linear gradient's opaque stops are read by the contrast checker. A radial
|
|
117
|
+
gradient is accepted as a value, but the checker cannot see through it, so text
|
|
118
|
+
over a radial gradient is judged against the surface below it.
|
|
119
|
+
|
|
120
|
+
## A dot grid
|
|
121
|
+
|
|
122
|
+
```html
|
|
123
|
+
<div data-id="home__dots" data-type="frame" style="width:100%;height:100%;background-image:radial-gradient(circle, #e3e3e3 1px, #00000000 1.5px);background-size:26px 26px"></div>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`background-size` takes a pair, so a repeatable texture is a value, not an
|
|
127
|
+
asset: the gradient draws one dot, and the size tiles it. The image repeats by
|
|
128
|
+
default, so no `background-repeat` is needed or available.
|
|
129
|
+
|
|
130
|
+
## Glass behind a floating bar
|
|
131
|
+
|
|
132
|
+
```html
|
|
133
|
+
<div data-id="home__bar" data-type="frame" style="position:absolute;left:16px;top:16px;padding:8px 12px;background-color:#ffffffb8;border:1px solid #ffffffcc;border-radius:999px;backdrop-filter:blur(20px) saturate(1.4)"></div>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`blur()` and `saturate()` only, in that order. The surface colour stays
|
|
137
|
+
translucent: the filter blurs what is behind the element, it does not supply a
|
|
138
|
+
background of its own. A renderer that ignores the filter still draws the
|
|
139
|
+
translucent fill, which is why the fill is written too.
|
|
140
|
+
|
|
141
|
+
## The most common refusals
|
|
142
|
+
|
|
143
|
+
| Written | Refused because | Write this |
|
|
144
|
+
|---|---|---|
|
|
145
|
+
| `animation` | No animation. A design file is a still. | remove it |
|
|
146
|
+
| `border-bottom` | Use border-width with four values for one edge. | `border-width: 0 0 1px 0` |
|
|
147
|
+
| `border-left` | Use border-width with four values for one edge. | `border-width: 0 0 0 1px` |
|
|
148
|
+
| `border-right` | Use border-width with four values for one edge. | `border-width: 0 1px 0 0` |
|
|
149
|
+
| `border-top` | Use border-width with four values for one edge. | `border-width: 1px 0 0 0` |
|
|
150
|
+
| `cursor` | The format describes appearance, not interaction. A cursor is behavior. | remove it |
|
|
151
|
+
| `font` | Write the longhand properties. | `font-family, font-size, font-weight and line-height` |
|
|
152
|
+
| `grid-gap` | The property is named gap. | `gap` |
|
|
153
|
+
| `grid-template-columns` | The format has no grid. Flex covers the same layouts. | `display:flex with flex:1 on the children` |
|
|
154
|
+
| `grid-template-rows` | The format has no grid. Flex covers the same layouts. | `display:flex with flex:1 on the children` |
|
|
155
|
+
| `margin-bottom` | Write the shorthand: margin: 0 0 8px 0. | `gap on the parent, or margin on this element` |
|
|
156
|
+
| `margin-left` | Write the shorthand: margin: 0 0 0 8px. | `gap on the parent, or margin on this element` |
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# Image catalogue
|
|
2
|
+
|
|
3
|
+
Unsplash photographs for a page that needs a picture and has not been told which
|
|
4
|
+
one to use. Grouped by what the page is looking for; every URL was requested from
|
|
5
|
+
`images.unsplash.com` and returned a 200 on 2026-10-25.
|
|
6
|
+
|
|
7
|
+
<!-- Hand-written data, not generated. scripts/check-images.mjs re-checks the URLs. -->
|
|
8
|
+
|
|
9
|
+
## How to use it
|
|
10
|
+
|
|
11
|
+
- **The user's image wins.** A URL, a file or a `.pen` image the user supplied is never
|
|
12
|
+
replaced. This catalogue is for the case where nobody said which picture to use.
|
|
13
|
+
- **Choose by subject, not by the nearest row.** A hero wants a wide landscape, a
|
|
14
|
+
feature card an object, an avatar a face, a testimonial one person.
|
|
15
|
+
- **Copy the `src` whole.** `?w=1080&q=80&fm=jpg` is part of the URL that was verified.
|
|
16
|
+
The `&` needs no escaping in the fragment you hand to `add`; the file is written with
|
|
17
|
+
`&`.
|
|
18
|
+
- **A small avatar may ask for less:** change `w=1080` to `w=400` and leave the rest
|
|
19
|
+
of the URL alone.
|
|
20
|
+
- **The credit goes in `data-credit`.** It never renders. The Licence does not require
|
|
21
|
+
it; keeping it makes a photo findable again the day the URL breaks.
|
|
22
|
+
- **No photo fits?** A solid colour or a linear gradient is the honest placeholder.
|
|
23
|
+
Never invent a `photo-…` id: a URL that resolves to nothing renders an empty box,
|
|
24
|
+
which is worse than a placeholder nobody mistakes for a photograph.
|
|
25
|
+
|
|
26
|
+
## Landscapes and scenery
|
|
27
|
+
|
|
28
|
+
Wide and tall scenes for heroes, cards and full-bleed backgrounds.
|
|
29
|
+
|
|
30
|
+
| src | Shows | Credit |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| `https://images.unsplash.com/photo-1634879036244-18870f8b804f?w=1080&q=80&fm=jpg` | Green meadow below snow-capped peaks at golden hour | Photo by Greg Š on Unsplash |
|
|
33
|
+
| `https://images.unsplash.com/photo-1542273917363-3b1817f69a2d?w=1080&q=80&fm=jpg` | Dense pine forest in thick morning fog | Photo by Marita Kavelashvili on Unsplash |
|
|
34
|
+
| `https://images.unsplash.com/photo-1696190288876-a2b40fcc63a9?w=1080&q=80&fm=jpg` | Dead tree stumps standing in a calm forest lake | Photo by Brett Mayson on Unsplash |
|
|
35
|
+
| `https://images.unsplash.com/photo-1638732984528-f255c9714619?w=1080&q=80&fm=jpg` | Smooth desert dunes fading into haze | Photo by raouf bedrani on Unsplash |
|
|
36
|
+
| `https://images.unsplash.com/photo-1570290887796-27624be22a60?w=1080&q=80&fm=jpg` | Waterfall pouring over dark basalt cliffs | Photo by Ben Eaton on Unsplash |
|
|
37
|
+
| `https://images.unsplash.com/photo-1685466695371-9fa8510634d0?w=1080&q=80&fm=jpg` | Pink poppies in bloom under a clear blue sky | Photo by Steve DiMatteo on Unsplash |
|
|
38
|
+
| `https://images.unsplash.com/photo-1491838592561-ab572ec2d2cb?w=1080&q=80&fm=jpg` | Sunbeams breaking through a misty forest | Photo by Mel on Unsplash |
|
|
39
|
+
| `https://images.unsplash.com/photo-1612441822281-778c7b2d4f38?w=1080&q=80&fm=jpg` | Golden sunrise over layered mountain ridges | Photo by Simon Lohmann on Unsplash |
|
|
40
|
+
| `https://images.unsplash.com/photo-1543988884-c01cfa7b41c2?w=1080&q=80&fm=jpg` | Turquoise water meeting a white sand beach, from above | Photo by Harry Holder on Unsplash |
|
|
41
|
+
| `https://images.unsplash.com/photo-1504596274545-5c136d4338f2?w=1080&q=80&fm=jpg` | Steep mountains flanking a deep blue fjord | Photo by Rod Long on Unsplash |
|
|
42
|
+
| `https://images.unsplash.com/photo-1726486061288-783c5cad8090?w=1080&q=80&fm=jpg` | Autumn trees around a still lake under grey sky | Photo by Linda Christiansen on Unsplash |
|
|
43
|
+
| `https://images.unsplash.com/photo-1665073526612-a2c3d7faddca?w=1080&q=80&fm=jpg` | Sunlit road curving through tall pine trees | Photo by Photos of Korea on Unsplash |
|
|
44
|
+
|
|
45
|
+
## Portraits and faces
|
|
46
|
+
|
|
47
|
+
One person, face readable at small sizes. Good for avatars, authors and a testimonial's photo.
|
|
48
|
+
|
|
49
|
+
| src | Shows | Credit |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| `https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=1080&q=80&fm=jpg` | Laughing woman in a red turtleneck, dark wavy hair | Photo from Unsplash |
|
|
52
|
+
| `https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=1080&q=80&fm=jpg` | Woman with slicked-back hair under blue studio light | Photo from Unsplash |
|
|
53
|
+
| `https://images.unsplash.com/photo-1524504388940-b1c1722653e1?w=1080&q=80&fm=jpg` | Woman with long blonde hair on a grey studio backdrop | Photo from Unsplash |
|
|
54
|
+
| `https://images.unsplash.com/photo-1554151228-14d9def656e4?w=1080&q=80&fm=jpg` | Freckled young woman with a braided bun, hand on chin | Photo from Unsplash |
|
|
55
|
+
| `https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=1080&q=80&fm=jpg` | Young woman with a red bob by a lake | Photo from Unsplash |
|
|
56
|
+
| `https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=1080&q=80&fm=jpg` | Man in a grey sweater, studio headshot | Photo from Unsplash |
|
|
57
|
+
| `https://images.unsplash.com/photo-1506794778202-cad84cf45f1d?w=1080&q=80&fm=jpg` | Bearded man in a grey knit sweater on black | Photo from Unsplash |
|
|
58
|
+
| `https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=1080&q=80&fm=jpg` | Smiling bearded man in a white t-shirt | Photo from Unsplash |
|
|
59
|
+
| `https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=1080&q=80&fm=jpg` | Man with grey hair and glasses in a green polo | Photo from Unsplash |
|
|
60
|
+
| `https://images.unsplash.com/photo-1560250097-0b93528c311a?w=1080&q=80&fm=jpg` | Man in glasses and a navy blazer by a window | Photo from Unsplash |
|
|
61
|
+
|
|
62
|
+
## Groups and people at work
|
|
63
|
+
|
|
64
|
+
More than one person: teams, friends, hands. For about sections, culture pages and testimonials.
|
|
65
|
+
|
|
66
|
+
| src | Shows | Credit |
|
|
67
|
+
|---|---|---|
|
|
68
|
+
| `https://images.unsplash.com/photo-1522071820081-009f0129c71c?w=1080&q=80&fm=jpg` | Team working on laptops at a long wooden table | Photo from Unsplash |
|
|
69
|
+
| `https://images.unsplash.com/photo-1521737604893-d14cc237f11d?w=1080&q=80&fm=jpg` | Group with headphones collaborating around a table | Photo from Unsplash |
|
|
70
|
+
| `https://images.unsplash.com/photo-1543269865-cbf427effbad?w=1080&q=80&fm=jpg` | Four young people talking around a cafe table | Photo from Unsplash |
|
|
71
|
+
| `https://images.unsplash.com/photo-1522202176988-66273c2fd55f?w=1080&q=80&fm=jpg` | Three young women laughing over laptops | Photo from Unsplash |
|
|
72
|
+
| `https://images.unsplash.com/photo-1495474472287-4d71bcdd2085?w=1080&q=80&fm=jpg` | Four hands toasting with coffee cups | Photo from Unsplash |
|
|
73
|
+
|
|
74
|
+
## Interiors and workspaces
|
|
75
|
+
|
|
76
|
+
Rooms and desks without a face: offices, a restaurant, a working setup.
|
|
77
|
+
|
|
78
|
+
| src | Shows | Credit |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| `https://images.unsplash.com/photo-1497366216548-37526070297c?w=1080&q=80&fm=jpg` | Modern empty office corridor with glass partitions | Photo from Unsplash |
|
|
81
|
+
| `https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?w=1080&q=80&fm=jpg` | Restaurant interior with dark wood tables and pendant lights | Photo from Unsplash |
|
|
82
|
+
| `https://images.unsplash.com/photo-1498050108023-c5249f4df085?w=1080&q=80&fm=jpg` | Programmer desk with an open laptop, code and coffee | Photo from Unsplash |
|
|
83
|
+
| `https://images.unsplash.com/photo-1517336714731-489689fd1ca8?w=1080&q=80&fm=jpg` | Half-open laptop lit with purple and orange neon | Photo from Unsplash |
|
|
84
|
+
| `https://images.unsplash.com/photo-1504384308090-c894fdcc538d?w=1080&q=80&fm=jpg` | Busy open-plan office with rows of people at laptops | Photo from Unsplash |
|
|
85
|
+
|
|
86
|
+
## Objects and food
|
|
87
|
+
|
|
88
|
+
A single product or plate on a quiet background: good for cards, features and lists.
|
|
89
|
+
|
|
90
|
+
| src | Shows | Credit |
|
|
91
|
+
|---|---|---|
|
|
92
|
+
| `https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=1080&q=80&fm=jpg` | Black over-ear headphones on a bright yellow background | Photo from Unsplash |
|
|
93
|
+
| `https://images.unsplash.com/photo-1526170375885-4d8ecf77b99f?w=1080&q=80&fm=jpg` | White instant camera on a plain white surface | Photo from Unsplash |
|
|
94
|
+
| `https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=1080&q=80&fm=jpg` | Red running shoe on a matching red background | Photo from Unsplash |
|
|
95
|
+
| `https://images.unsplash.com/photo-1523275335684-37898b6baf30?w=1080&q=80&fm=jpg` | Two smartwatches with blank round faces on white | Photo from Unsplash |
|
|
96
|
+
| `https://images.unsplash.com/photo-1512621776951-a57141f2eefd?w=1080&q=80&fm=jpg` | Colourful salad bowl with avocado, tomatoes and chickpeas | Photo from Unsplash |
|
|
97
|
+
| `https://images.unsplash.com/photo-1567620905732-2d1ec7ab7445?w=1080&q=80&fm=jpg` | Pancake stack with syrup poured from a small cup | Photo from Unsplash |
|
|
98
|
+
|
|
99
|
+
## Sport, hobbies and daily life
|
|
100
|
+
|
|
101
|
+
Exercise, shopping, music, study and a cafe: for fitness, retail, education and
|
|
102
|
+
lifestyle pages.
|
|
103
|
+
|
|
104
|
+
| src | Shows | Credit |
|
|
105
|
+
|---|---|---|
|
|
106
|
+
| `https://images.unsplash.com/photo-1517836357463-d25dfeac3438?w=1080&q=80&fm=jpg` | Man deadlifting a barbell in a dark gym | Photo from Unsplash |
|
|
107
|
+
| `https://images.unsplash.com/photo-1571019613454-1cb2f99b2d8b?w=1080&q=80&fm=jpg` | Woman doing sit-ups on a mat by a bright window | Photo from Unsplash |
|
|
108
|
+
| `https://images.unsplash.com/photo-1476480862126-209bfaa8edc8?w=1080&q=80&fm=jpg` | Runner's legs climbing weathered concrete steps | Photo from Unsplash |
|
|
109
|
+
| `https://images.unsplash.com/photo-1483985988355-763728e1935b?w=1080&q=80&fm=jpg` | Woman in sunglasses carrying shopping bags outside | Photo from Unsplash |
|
|
110
|
+
| `https://images.unsplash.com/photo-1445205170230-053b83016050?w=1080&q=80&fm=jpg` | Clothing racks full of coats in a boutique | Photo from Unsplash |
|
|
111
|
+
| `https://images.unsplash.com/photo-1554118811-1e0d58224f24?w=1080&q=80&fm=jpg` | Customers and a barista inside a plant-filled cafe | Photo from Unsplash |
|
|
112
|
+
| `https://images.unsplash.com/photo-1511671782779-c97d3d27a1d4?w=1080&q=80&fm=jpg` | Vintage silver microphone against coloured blurred lights | Photo from Unsplash |
|
|
113
|
+
| `https://images.unsplash.com/photo-1503676260728-1c00da094a0b?w=1080&q=80&fm=jpg` | Stack of books, a red apple and alphabet blocks | Photo from Unsplash |
|
|
114
|
+
| `https://images.unsplash.com/photo-1416879595882-3373a0480b5b?w=1080&q=80&fm=jpg` | Gardening flat lay with a soil scoop and spilled potting mix | Photo from Unsplash |
|
|
115
|
+
|
|
116
|
+
## Cities and buildings
|
|
117
|
+
|
|
118
|
+
Streets, skylines and a house at dusk: for travel, real estate and city pages.
|
|
119
|
+
|
|
120
|
+
| src | Shows | Credit |
|
|
121
|
+
|---|---|---|
|
|
122
|
+
| `https://images.unsplash.com/photo-1449824913935-59a10b8d2000?w=1080&q=80&fm=jpg` | New York avenue with skyscrapers and yellow taxis | Photo from Unsplash |
|
|
123
|
+
| `https://images.unsplash.com/photo-1477959858617-67f85cf4f1df?w=1080&q=80&fm=jpg` | Aerial Chicago skyline at dusk beside the lake | Photo from Unsplash |
|
|
124
|
+
| `https://images.unsplash.com/photo-1519501025264-65ba15a82390?w=1080&q=80&fm=jpg` | Wet New York street with cars at dusk between towers | Photo from Unsplash |
|
|
125
|
+
| `https://images.unsplash.com/photo-1494526585095-c41746248156?w=1080&q=80&fm=jpg` | Modern house exterior at dusk with a warm lit entrance | Photo from Unsplash |
|
|
126
|
+
|
|
127
|
+
## Textures and backgrounds
|
|
128
|
+
|
|
129
|
+
No subject to recognise: gradients, ink and water for a back layer behind text.
|
|
130
|
+
|
|
131
|
+
| src | Shows | Credit |
|
|
132
|
+
|---|---|---|
|
|
133
|
+
| `https://images.unsplash.com/photo-1557682250-33bd709cbe85?w=1080&q=80&fm=jpg` | Abstract purple to pink gradient | Photo from Unsplash |
|
|
134
|
+
| `https://images.unsplash.com/photo-1557682224-5b8590cd9ec5?w=1080&q=80&fm=jpg` | Abstract blue to orange-red gradient | Photo from Unsplash |
|
|
135
|
+
| `https://images.unsplash.com/photo-1541701494587-cb58502866ab?w=1080&q=80&fm=jpg` | Blue and orange ink swirling in dark water | Photo from Unsplash |
|
|
136
|
+
| `https://images.unsplash.com/photo-1674005619701-285543ad3a40?w=1080&q=80&fm=jpg` | Calm blue water surface with soft ripples | Photo by Ch Photography on Unsplash |
|
|
137
|
+
|
|
138
|
+
## Animals
|
|
139
|
+
|
|
140
|
+
For pets, farming and anything that wants a friendly non-human.
|
|
141
|
+
|
|
142
|
+
| src | Shows | Credit |
|
|
143
|
+
|---|---|---|
|
|
144
|
+
| `https://images.unsplash.com/photo-1750363890360-2fc2f5136187?w=1080&q=80&fm=jpg` | Brown cow grazing in a lush green meadow | Photo by Seval Torun on Unsplash |
|
|
145
|
+
| `https://images.unsplash.com/photo-1514888286974-6c03e2ca1dba?w=1080&q=80&fm=jpg` | Black and white cat resting on a wooden railing | Photo from Unsplash |
|
|
146
|
+
| `https://images.unsplash.com/photo-1543466835-00a7907e9de1?w=1080&q=80&fm=jpg` | Beagle looking up with its tongue out | Photo from Unsplash |
|
|
147
|
+
|
|
148
|
+
## Licence
|
|
149
|
+
|
|
150
|
+
The photos come from [Unsplash](https://unsplash.com) under the
|
|
151
|
+
[Unsplash License](https://unsplash.com/license): free to download, copy, modify and
|
|
152
|
+
use, including commercially, without permission and without attribution. Three things
|
|
153
|
+
that licence does not cover, and that matter to a design:
|
|
154
|
+
|
|
155
|
+
- **Reselling or compiling.** You cannot sell unmodified copies, and you cannot build a
|
|
156
|
+
competing photo service out of them. A design, a mockup and a shipped page are fine.
|
|
157
|
+
- **Unsplash+.** Its paid photos are a different licence. None are in this file.
|
|
158
|
+
- **People and trademarks.** The faces above belong to real people with rights of
|
|
159
|
+
publicity; the object photos may show a brand. A stock face in an avatar or a mockup
|
|
160
|
+
is ordinary use. A shipped page that presents one as a real customer's testimonial,
|
|
161
|
+
or a logo as your product, is not covered by the photo licence.
|
|
162
|
+
|
|
163
|
+
The images are **hotlinked**, never copied into the repository: the design file stays
|
|
164
|
+
text, and the photos render only while there is a connection. A photo its author
|
|
165
|
+
deletes stops resolving, so run `npm run images:check` before a release that depends
|
|
166
|
+
on them; it prints every URL that no longer resolves.
|
|
167
|
+
|
|
168
|
+
A credit reads `Photo by <name> on Unsplash` when the photographer's name was recorded
|
|
169
|
+
(the photos inherited from `examples/miniprogram.pen`), and `Photo from Unsplash` when
|
|
170
|
+
it was not. The licence does not require attribution, so either one is a complete
|
|
171
|
+
credit; the first is simply easier to trace.
|