@labcat2020/animation-lab 0.1.2
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 +61 -0
- package/package.json +45 -0
- package/scripts/link-packages.mjs +36 -0
- package/src/components/InstagramCTA.astro +99 -0
- package/src/layouts/BaseLayout.astro +25 -0
- package/src/layouts/SketchLayout.astro +49 -0
- package/src/styles/global.scss +79 -0
- package/src/styles/mixins/breakpoints.scss +65 -0
- package/src/styles/variables.scss +20 -0
- package/src/vite.mjs +64 -0
- package/templates/pnpm-workspace.yaml +10 -0
package/README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# @labcat2020/animation-lab
|
|
2
|
+
|
|
3
|
+
Shared Astro layouts, components, styles, and Vite helpers for **Animation Lab** (formerly `animations.labcat.nz`) series sites — e.g. `triangles`, `donuts`.
|
|
4
|
+
|
|
5
|
+
> Renamed from `@labcat2020/astro-animations` → `@labcat2020/animation-lab` (Sep 2026). Now published to npm (was GitHub Packages).
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
```bash
|
|
9
|
+
pnpm add @labcat2020/animation-lab
|
|
10
|
+
# peer deps required in host Astro app:
|
|
11
|
+
pnpm add astro sass-embedded
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Exports
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"./layouts/*": "./src/layouts/*",
|
|
18
|
+
"./components/*": "./src/components/*",
|
|
19
|
+
"./styles/*": "./src/styles/*",
|
|
20
|
+
"./vite": "./src/vite.mjs"
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Usage (Astro)
|
|
25
|
+
|
|
26
|
+
`astro.config.mjs`:
|
|
27
|
+
```js
|
|
28
|
+
import { defineConfig } from 'astro/config';
|
|
29
|
+
import { astroAnimationsViteConfig, astroAnimationsViteAliases, astroAnimationsScssPrepend } from '@labcat2020/animation-lab/vite';
|
|
30
|
+
|
|
31
|
+
export default defineConfig({
|
|
32
|
+
vite: {
|
|
33
|
+
...astroAnimationsViteConfig(),
|
|
34
|
+
resolve: { alias: { ...astroAnimationsViteAliases(), '@': '/src' } },
|
|
35
|
+
css: { preprocessorOptions: { scss: { additionalData: astroAnimationsScssPrepend() } } }
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
- `astroAnimationsViteConfig()` — injects `p5.sound` preamble (binds global `p5` before `p5.sound` IIFE) + marks audio-react side-effects as non-tree-shakable.
|
|
40
|
+
- `astroAnimationsViteAliases()` — `@lib` → `@labcat2020/p5.audioreactive` (legacy series import path).
|
|
41
|
+
- `astroAnimationsScssPrepend()` — prepends `styles/mixins/breakpoints.scss`.
|
|
42
|
+
|
|
43
|
+
Layouts:
|
|
44
|
+
```astro
|
|
45
|
+
import BaseLayout from '@labcat2020/animation-lab/layouts/BaseLayout.astro';
|
|
46
|
+
import SketchLayout from '@labcat2020/animation-lab/layouts/SketchLayout.astro';
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Dev helper
|
|
50
|
+
|
|
51
|
+
Series repos linking local hub (sibling `../animations.labcat.nz`):
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pnpm run postinstall # labcat-link-packages (symlinks packages/*)
|
|
55
|
+
# or
|
|
56
|
+
npx labcat-link-packages
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## License
|
|
60
|
+
|
|
61
|
+
MIT — LABCAT
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@labcat2020/animation-lab",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Shared Astro layouts, components, and styles for Animation Lab series sites",
|
|
6
|
+
"exports": {
|
|
7
|
+
"./layouts/*": "./src/layouts/*",
|
|
8
|
+
"./components/*": "./src/components/*",
|
|
9
|
+
"./styles/*": "./src/styles/*",
|
|
10
|
+
"./vite": "./src/vite.mjs"
|
|
11
|
+
},
|
|
12
|
+
"bin": {
|
|
13
|
+
"labcat-link": "./scripts/link-packages.mjs",
|
|
14
|
+
"labcat-link-packages": "./scripts/link-packages.mjs"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"src",
|
|
18
|
+
"scripts",
|
|
19
|
+
"templates"
|
|
20
|
+
],
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"normalize.css": "^8.0.1"
|
|
26
|
+
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"astro": "^6.0.8",
|
|
29
|
+
"sass-embedded": "^1.98.0"
|
|
30
|
+
},
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"author": "LABCAT (labcat.nz)",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/LABCAT/animations.labcat.nz.git",
|
|
36
|
+
"directory": "packages/animation-lab"
|
|
37
|
+
},
|
|
38
|
+
"keywords": [
|
|
39
|
+
"astro",
|
|
40
|
+
"animation",
|
|
41
|
+
"labcat",
|
|
42
|
+
"p5",
|
|
43
|
+
"generative"
|
|
44
|
+
]
|
|
45
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { access, mkdir, readdir, rm, symlink } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
const seriesRoot = process.cwd();
|
|
6
|
+
const labcatPackages =
|
|
7
|
+
process.env.LABCAT_PACKAGES ??
|
|
8
|
+
path.resolve(seriesRoot, '../animations.labcat.nz/packages');
|
|
9
|
+
const linkDir =
|
|
10
|
+
process.env.LABCAT_LINK_DIR ?? path.join(seriesRoot, 'packages');
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
await access(labcatPackages);
|
|
14
|
+
} catch {
|
|
15
|
+
console.warn(`[link] @labcat packages not found at ${labcatPackages}`);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const entries = await readdir(labcatPackages, { withFileTypes: true });
|
|
20
|
+
const packageNames = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
21
|
+
|
|
22
|
+
if (packageNames.length === 0) {
|
|
23
|
+
console.warn('[link] No @labcat packages found.');
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
await mkdir(linkDir, { recursive: true });
|
|
28
|
+
|
|
29
|
+
for (const name of packageNames) {
|
|
30
|
+
const target = path.join(labcatPackages, name);
|
|
31
|
+
const link = path.join(linkDir, name);
|
|
32
|
+
await rm(link, { recursive: true, force: true });
|
|
33
|
+
await symlink(target, link, process.platform === 'win32' ? 'junction' : 'dir');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
console.log(`[link] packages/ → ${labcatPackages} (${packageNames.join(', ')})`);
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
---
|
|
2
|
+
// InstagramCTA component with BEM structure
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
<div class="instagram-cta">
|
|
6
|
+
<a
|
|
7
|
+
href="https://www.instagram.com/labcat2020/"
|
|
8
|
+
class="instagram-cta__link"
|
|
9
|
+
target="_blank"
|
|
10
|
+
rel="noopener noreferrer"
|
|
11
|
+
>
|
|
12
|
+
<svg
|
|
13
|
+
class="instagram-cta__icon"
|
|
14
|
+
viewBox="0 0 169.06 169.06"
|
|
15
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
16
|
+
>
|
|
17
|
+
<path
|
|
18
|
+
d="M122.406,0H46.654C20.929,0,0,20.93,0,46.655v75.752c0,25.726,20.929,46.655,46.654,46.655h75.752 c25.727,0,46.656-20.93,46.656-46.655V46.655C169.063,20.93,148.133,0,122.406,0z M154.063,122.407 c0,17.455-14.201,31.655-31.656,31.655H46.654C29.2,154.063,15,139.862,15,122.407V46.655C15,29.201,29.2,15,46.654,15h75.752 c17.455,0,31.656,14.201,31.656,31.655V122.407z"
|
|
19
|
+
></path>
|
|
20
|
+
<path
|
|
21
|
+
d="m84.531 40.97c-24.021 0-43.563 19.542-43.563 43.563 0 24.02 19.542 43.561 43.563 43.561s43.563-19.541 43.563-43.561c0-24.021-19.542-43.563-43.563-43.563zm0 72.123c-15.749 0-28.563-12.812-28.563-28.561 0-15.75 12.813-28.563 28.563-28.563s28.563 12.813 28.563 28.563c0 15.749-12.814 28.561-28.563 28.561z"
|
|
22
|
+
></path>
|
|
23
|
+
<path
|
|
24
|
+
d="m129.92 28.251c-2.89 0-5.729 1.17-7.77 3.22-2.051 2.04-3.23 4.88-3.23 7.78 0 2.891 1.18 5.73 3.23 7.78 2.04 2.04 4.88 3.22 7.77 3.22 2.9 0 5.73-1.18 7.78-3.22 2.05-2.05 3.22-4.89 3.22-7.78 0-2.9-1.17-5.74-3.22-7.78-2.04-2.05-4.88-3.22-7.78-3.22z"
|
|
25
|
+
></path>
|
|
26
|
+
</svg>
|
|
27
|
+
<span class="instagram-cta__text">
|
|
28
|
+
<span class="instagram-cta__action">Follow</span>
|
|
29
|
+
@labcat2020
|
|
30
|
+
</span>
|
|
31
|
+
</a>
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
<style lang="scss">
|
|
35
|
+
@import '../styles/mixins/breakpoints.scss';
|
|
36
|
+
|
|
37
|
+
.instagram-cta {
|
|
38
|
+
--shadow-colour: var(--cyan);
|
|
39
|
+
position: fixed;
|
|
40
|
+
bottom: 10px;
|
|
41
|
+
left: 10px;
|
|
42
|
+
z-index: 1000;
|
|
43
|
+
background: var(--black);
|
|
44
|
+
border-radius: 8px;
|
|
45
|
+
|
|
46
|
+
&__link {
|
|
47
|
+
display: flex;
|
|
48
|
+
align-items: center;
|
|
49
|
+
gap: 8px;
|
|
50
|
+
padding: 8px 12px;
|
|
51
|
+
border-radius: 8px;
|
|
52
|
+
backdrop-filter: blur(10px);
|
|
53
|
+
transition: all 0.5s;
|
|
54
|
+
color: var(--white);
|
|
55
|
+
font-weight: 700;
|
|
56
|
+
text-decoration: none;
|
|
57
|
+
box-shadow:
|
|
58
|
+
0 0 24px var(--shadow-colour),
|
|
59
|
+
0 0 12px var(--shadow-colour),
|
|
60
|
+
0 0 6px var(--shadow-colour),
|
|
61
|
+
0 0 3px var(--shadow-colour);
|
|
62
|
+
|
|
63
|
+
&:hover {
|
|
64
|
+
--shadow-colour: var(--pink);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
&__icon {
|
|
69
|
+
--size: 22px;
|
|
70
|
+
width: var(--size);
|
|
71
|
+
height: var(--size);
|
|
72
|
+
border-radius: 8px;
|
|
73
|
+
fill: currentColor;
|
|
74
|
+
transition: all 0.5s;
|
|
75
|
+
|
|
76
|
+
@include media-breakpoint-up(md) {
|
|
77
|
+
--size: 24px;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
&__text {
|
|
82
|
+
--size: 16px;
|
|
83
|
+
font-size: var(--size);
|
|
84
|
+
-webkit-text-stroke: 1px var(--black);
|
|
85
|
+
|
|
86
|
+
@include media-breakpoint-up(md) {
|
|
87
|
+
--size: 18px;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
&__action {
|
|
92
|
+
display: none;
|
|
93
|
+
|
|
94
|
+
@include media-breakpoint-up(md) {
|
|
95
|
+
display: inline;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
</style>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
import '../styles/global.scss';
|
|
3
|
+
|
|
4
|
+
const { title = 'Sketchbook', description = '' } = Astro.props;
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<!doctype html>
|
|
8
|
+
<html lang="en">
|
|
9
|
+
<head>
|
|
10
|
+
<meta charset="utf-8" />
|
|
11
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
12
|
+
<title>{title}</title>
|
|
13
|
+
{description && <meta name="description" content={description} />}
|
|
14
|
+
<link rel="manifest" href="manifest.json"/>
|
|
15
|
+
<link rel="icon" href="https://labcat.nz/favicon.ico" sizes="any"/>
|
|
16
|
+
<link rel="icon" type="image/svg+xml" href="https://labcat.nz/icon.svg"/>
|
|
17
|
+
<link rel="apple-touch-icon" href="https://labcat.nz/apple-touch-icon.png"/>
|
|
18
|
+
<link rel="dns-prefetch" href="//fonts.googleapis.com"/>
|
|
19
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="true"/>
|
|
20
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Orbitron:wght@500;600;800;900&family=Teko:wght@700&display=swap" id="fonts">
|
|
21
|
+
</head>
|
|
22
|
+
<body>
|
|
23
|
+
<slot />
|
|
24
|
+
</body>
|
|
25
|
+
</html>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
import BaseLayout from './BaseLayout.astro';
|
|
3
|
+
import InstagramCTA from '../components/InstagramCTA.astro';
|
|
4
|
+
|
|
5
|
+
const { title = 'Sketch', description = '' } = Astro.props;
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
<BaseLayout title={title} description={description}>
|
|
9
|
+
<slot />
|
|
10
|
+
<div id="p5_loading"></div>
|
|
11
|
+
<div id="loader" class="loading">
|
|
12
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
|
13
|
+
<path
|
|
14
|
+
fill="none"
|
|
15
|
+
stroke-width="8"
|
|
16
|
+
stroke-dasharray="42.76482137044271 42.76482137044271"
|
|
17
|
+
d="M24.3 30C11.4 30 5 43.3 5 50s6.4 20 19.3 20c19.3 0 32.1-40 51.4-40 C88.6 30 95 43.3 95 50s-6.4 20-19.3 20C56.4 70 43.6 30 24.3 30z"
|
|
18
|
+
stroke-linecap="round"
|
|
19
|
+
style="transform:scale(0.8);transform-origin:50px 50px"
|
|
20
|
+
>
|
|
21
|
+
<animate
|
|
22
|
+
attributeName="stroke-dashoffset"
|
|
23
|
+
repeatCount="indefinite"
|
|
24
|
+
dur="1s"
|
|
25
|
+
keyTimes="0;1"
|
|
26
|
+
values="0;256.58892822265625"></animate>
|
|
27
|
+
</path>
|
|
28
|
+
</svg>
|
|
29
|
+
</div>
|
|
30
|
+
<main id="sketch-canvas"></main>
|
|
31
|
+
<!-- Play Icon -->
|
|
32
|
+
<svg
|
|
33
|
+
id="play-icon"
|
|
34
|
+
tabindex="0"
|
|
35
|
+
role="button"
|
|
36
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
37
|
+
height="120"
|
|
38
|
+
width="120"
|
|
39
|
+
viewBox="0 0 24 24"
|
|
40
|
+
class="play-icon"
|
|
41
|
+
>
|
|
42
|
+
<path d="M0 0h24v24H0z" fill="none"></path>
|
|
43
|
+
<path
|
|
44
|
+
d="M10 16.5l6-4.5-6-4.5v9zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"
|
|
45
|
+
></path>
|
|
46
|
+
</svg>
|
|
47
|
+
|
|
48
|
+
<!-- <InstagramCTA /> -->
|
|
49
|
+
</BaseLayout>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Import normalize.css for consistent base styling
|
|
2
|
+
@import "./variables";
|
|
3
|
+
@import "./mixins/breakpoints";
|
|
4
|
+
@import "normalize.css";
|
|
5
|
+
|
|
6
|
+
$cursor-color: white;
|
|
7
|
+
|
|
8
|
+
body {
|
|
9
|
+
overflow: hidden;
|
|
10
|
+
font-family: Orbitron,sans-serif;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.loading {
|
|
14
|
+
display: flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
position: fixed;
|
|
17
|
+
inset: 0;
|
|
18
|
+
z-index: 1;
|
|
19
|
+
background: var(--gradient-bg);
|
|
20
|
+
background-blend-mode: var(--gradient-blend-mode);
|
|
21
|
+
transform: rotate(-180deg);
|
|
22
|
+
transition: opacity 3s;
|
|
23
|
+
opacity: 1;
|
|
24
|
+
|
|
25
|
+
&--complete {
|
|
26
|
+
opacity: 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
svg {
|
|
30
|
+
margin: auto;
|
|
31
|
+
width: 10rem;
|
|
32
|
+
height: 10rem;
|
|
33
|
+
background: transparent;
|
|
34
|
+
shape-rendering: auto;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
path {
|
|
38
|
+
fill: none;
|
|
39
|
+
stroke: #ff0cb8;
|
|
40
|
+
transform: scale(0.8);
|
|
41
|
+
transform-origin: 50px 50px;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.p5Canvas,
|
|
46
|
+
#defaultCanvas0 {
|
|
47
|
+
position: relative;
|
|
48
|
+
z-index: 1;
|
|
49
|
+
background: var(--canvas-complex-bg);
|
|
50
|
+
background-blend-mode: var(--canvas-complex-blend-mode);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.p5Canvas--cursor-play {
|
|
54
|
+
cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32'><polygon points='8,6 26,16 8,26' fill='#{$cursor-color}'/></svg>") 8 8, pointer;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.p5Canvas--cursor-pause {
|
|
58
|
+
cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32'><rect x='8' y='6' width='4' height='20' fill='#{$cursor-color}'/><rect x='20' y='6' width='4' height='20' fill='#{$cursor-color}'/></svg>") 8 8, pointer;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
#play-icon {
|
|
62
|
+
position: fixed;
|
|
63
|
+
top: 20px;
|
|
64
|
+
right: 20px;
|
|
65
|
+
width: 120px;
|
|
66
|
+
height: 120px;
|
|
67
|
+
fill: var(--play-icon-color);
|
|
68
|
+
visibility: hidden;
|
|
69
|
+
z-index: 1;
|
|
70
|
+
opacity: 0;
|
|
71
|
+
transition: opacity 1s;
|
|
72
|
+
cursor: pointer;
|
|
73
|
+
|
|
74
|
+
&.fade-in {
|
|
75
|
+
opacity: 1;
|
|
76
|
+
visibility: visible;
|
|
77
|
+
z-index: 2;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Grid breakpoints
|
|
2
|
+
$grid-breakpoints: (
|
|
3
|
+
xs: 0,
|
|
4
|
+
sm: 576px,
|
|
5
|
+
md: 768px,
|
|
6
|
+
lg: 1024px,
|
|
7
|
+
xl: 1280px,
|
|
8
|
+
xxl: 1440px,
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
// Helper function to get minimum breakpoint value
|
|
12
|
+
@function breakpoint-min($name, $breakpoints: $grid-breakpoints) {
|
|
13
|
+
$min: map-get($breakpoints, $name);
|
|
14
|
+
@if $min != 0 {
|
|
15
|
+
@return $min;
|
|
16
|
+
}
|
|
17
|
+
@return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Media of at least the minimum breakpoint width. No query for the smallest breakpoint.
|
|
21
|
+
// Makes the @content apply to the given breakpoint and wider.
|
|
22
|
+
@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) {
|
|
23
|
+
$min: breakpoint-min($name, $breakpoints);
|
|
24
|
+
@if $min {
|
|
25
|
+
@media (min-width: $min) {
|
|
26
|
+
@content;
|
|
27
|
+
}
|
|
28
|
+
} @else {
|
|
29
|
+
@content;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Media of at most the maximum breakpoint width. No query for the largest breakpoint.
|
|
34
|
+
// Makes the @content apply to the given breakpoint and narrower.
|
|
35
|
+
@mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) {
|
|
36
|
+
$max: map-get($breakpoints, $name) - 0.02;
|
|
37
|
+
@if $max {
|
|
38
|
+
@media (max-width: $max) {
|
|
39
|
+
@content;
|
|
40
|
+
}
|
|
41
|
+
} @else {
|
|
42
|
+
@content;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Media that spans multiple breakpoint widths.
|
|
47
|
+
// Makes the @content apply between the min and max breakpoints
|
|
48
|
+
@mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) {
|
|
49
|
+
$min: breakpoint-min($lower, $breakpoints);
|
|
50
|
+
$max: map-get($breakpoints, $upper) - 0.02;
|
|
51
|
+
|
|
52
|
+
@if $min != null and $max != null {
|
|
53
|
+
@media (min-width: $min) and (max-width: $max) {
|
|
54
|
+
@content;
|
|
55
|
+
}
|
|
56
|
+
} @else if $max == null {
|
|
57
|
+
@include media-breakpoint-up($lower, $breakpoints) {
|
|
58
|
+
@content;
|
|
59
|
+
}
|
|
60
|
+
} @else if $min == null {
|
|
61
|
+
@include media-breakpoint-down($upper, $breakpoints) {
|
|
62
|
+
@content;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Brand Colors
|
|
2
|
+
:root {
|
|
3
|
+
--cyan: #0cdbf5;
|
|
4
|
+
--pink: #ff0cb8;
|
|
5
|
+
--white: #fff;
|
|
6
|
+
--black: #000;
|
|
7
|
+
--gradient-bg: linear-gradient(0deg,
|
|
8
|
+
rgba(0, 0, 0, 1) -8.35%,
|
|
9
|
+
rgba(29, 22, 87, 1) -5.1%,
|
|
10
|
+
rgba(51, 65, 174, 1) 28.53%,
|
|
11
|
+
rgba(59, 82, 208, 1) 43.72%,
|
|
12
|
+
rgba(53, 100, 213, 1) 51.31%,
|
|
13
|
+
rgba(37, 146, 225, 1) 67.59%,
|
|
14
|
+
rgba(12, 219, 245, 1) 89.28%,
|
|
15
|
+
rgba(0, 255, 255, 1) 100.13%);
|
|
16
|
+
--play-icon-color: white;
|
|
17
|
+
--canvas-bg: transparent;
|
|
18
|
+
--canvas-complex-bg: none;
|
|
19
|
+
--canvas-complex-blend-mode: normal;
|
|
20
|
+
}
|
package/src/vite.mjs
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { fileURLToPath } from 'node:url';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
const packageRoot = fileURLToPath(new URL('.', import.meta.url));
|
|
5
|
+
|
|
6
|
+
/** Bind p5 before p5.sound's IIFE — bare global `p5` is tree-shaken in production otherwise. */
|
|
7
|
+
function p5SoundPreamblePlugin() {
|
|
8
|
+
return {
|
|
9
|
+
name: 'labcat-p5-sound-preamble',
|
|
10
|
+
enforce: 'pre',
|
|
11
|
+
transform(code, id) {
|
|
12
|
+
const normalized = id.replace(/\\/g, '/');
|
|
13
|
+
if (!normalized.includes('p5.sound/dist/p5.sound.js')) return null;
|
|
14
|
+
if (code.includes('labcat-p5-sound-preamble')) return null;
|
|
15
|
+
return {
|
|
16
|
+
code: [
|
|
17
|
+
"import __labcatP5 from 'p5';",
|
|
18
|
+
'const p5 = globalThis.p5 ?? __labcatP5;',
|
|
19
|
+
'globalThis.p5 = p5;',
|
|
20
|
+
'/* labcat-p5-sound-preamble */',
|
|
21
|
+
code,
|
|
22
|
+
].join('\n'),
|
|
23
|
+
moduleSideEffects: true,
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Vite/Astro SCSS hook for series repos consuming @labcat2020/animation-lab. */
|
|
30
|
+
export function astroAnimationsScssPrepend() {
|
|
31
|
+
const breakpoints = path.join(packageRoot, 'styles/mixins/breakpoints.scss');
|
|
32
|
+
return `@import "${breakpoints.replace(/\\/g, '/')}";`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Shared Vite config — keeps p5.sound + p5.audioreactive prototype patches in production builds. */
|
|
36
|
+
export function astroAnimationsViteConfig() {
|
|
37
|
+
return {
|
|
38
|
+
plugins: [p5SoundPreamblePlugin()],
|
|
39
|
+
build: {
|
|
40
|
+
rollupOptions: {
|
|
41
|
+
treeshake: {
|
|
42
|
+
moduleSideEffects(id) {
|
|
43
|
+
if (id.includes('p5.sound')) return true;
|
|
44
|
+
// Only the three side-effect entry files from p5.audioreactive; other helpers are tree-shakable
|
|
45
|
+
if (
|
|
46
|
+
id.includes('p5.audioreactive/src/p5.audioReact.js') ||
|
|
47
|
+
id.includes('p5.audioreactive/src/p5.soundBoot.js') ||
|
|
48
|
+
id.includes('p5.audioreactive/src/p5.setGlobalP5.js')
|
|
49
|
+
)
|
|
50
|
+
return true;
|
|
51
|
+
return undefined;
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Vite aliases — `@lib/*` resolves to `@labcat2020/p5.audioreactive/*` (legacy series import paths). */
|
|
60
|
+
export function astroAnimationsViteAliases() {
|
|
61
|
+
return {
|
|
62
|
+
'@lib': '@labcat2020/p5.audioreactive',
|
|
63
|
+
};
|
|
64
|
+
}
|