两条路径的交汇
今年夏天我创建了个人项目平台,这并非完全有意为之。当我意识到自己的创作过程走向时,已经在这条路上走了一段距离。
路径一:必要的快乐空间
作为设计师,并非每天都充满灵感。特别是当设计与AI领域变化如此之快时,有时很难看清大局。
作为补救措施,我开始构建一个情绪板作为我的快乐空间。每当我遇到让我微笑的参考时,就把它放在那里。它有我梦想办公室的部分;引起我共鸣的引语和想法;以及随机的图像片段,这些片段在一起感觉就像我~或者至少是一个设计师版本的我。我开始添加自己的涂鸦、笔记和关于目的的思考:我为什么还在做这个?作为设计师我在寻找什么?
路径二:Instagram实验
2022年12月的一个晚上,我和一位设计师朋友喝酒。我们只是为了好玩而制作随机的东西。在工作中,我已经转向更多的管理角色,我怀念设计。
然后我想:为什么不把它放到网上?于是我创建了一个Instagram账号并发布了我的第一个Processing草图。
我做得越多,就越想继续做。随着时间的推移,这个习惯成了我的一部分。草图变得具有交互性,但令我困扰的是它们只能在本地运行~只有我能与它们互动。我也开始分享快速教程,并对收到如此多的积极回应感到惊讶,这些回应来自那些受到启发想要自己创作的人。
构建平台
既然我们在Codrops上,让我们谈谈代码。我有PHP和JavaScript的背景~老派的,在ES6或TypeScript之前,更不用说Vue或React了。我想用这个项目来学习新东西。
经过一些研究,我决定使用Nuxt.js。根据我的了解,它比Next.js更容易设置。而且由于我的平台不太可能很快扩展,我认为它可以胜任。我几年前也玩过Prismic CMS。轻量级,功能不多,但对我来说很好。所以我看了一些Nuxt.js+Prismic教程,然后就开始了。
英雄区域
我知道我想要交互式组件。让访问者立即感受到我的作品的东西。让我们从英雄区域开始。
在摩擦中发现美
用鼠标在画布上绘制对象,简单明了。我希望对象与自然有联系~某种生长、繁荣的东西~就像你承担许多个人项目时会做的那样。
在我的第一个草图中,花朵从小到大缩放,实际上是生长的。但后来我想:有多少次我在一个草图上卡住,对一个行不通的想法感到沮丧?所以我决定线性增长不会诚实。大多数时候,当我从事项目时,我的头脑到处都是。事物应该随机缩放,它们甚至不需要在宽度和高度上匹配。我喜欢这样,它反映了我工作中控制与混乱之间的张力。下面你会看到实现这一点的代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
/**
* 获取下一张图像的一部分
*/
public getPortion(): p5.Image {
// 获取原始图像
const original = this.getNext();
if (! original) return null;
// 源
const ow = original.width;
const oh = original.height;
const sx = Math.random() * ow;
const sy = Math.random() * oh;
// 剩余部分
const loW = ow - sx;
const loH = oh - sy;
let sw = Math.round(loW * Math.random()) + 10;
let sh = Math.round(loH * Math.random()) + 10;
// 目标
const dx = 0;
const dy = 0;
const dw = sw;
const dh = sh;
// 创建新图像
const copy = this.p.createImage(dw, dh);
copy.copy(original, sx, sy, sw, sh, dx, dy, dw, dh);
return copy;
}
public getRandomSizedPortion(): p5.Image {
// 获取部分
const img = this.getPortion();
if (! img) return null;
// 随机大小
const maxSize = this.p.width * .1;
img.resize(this.p.random(10,maxSize), this.p.random(10,maxSize));
return img;
}
|
页脚
为了平衡英雄区域,我也让页脚具有交互性。我使用了一个较旧的草图作为基础,添加了深度和纹理,使其感觉有点像抽象的海洋。
对我来说,它带来了一种平静和专注的感觉~具有微妙的垂直运动,以及当你沿着x轴移动鼠标时变化的色调。下面的代码片段应该让你了解它是如何工作的,但原始草图可以在平台上下载。所以如果你好奇,就去玩玩吧。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
/**
* 计算所有数据
*/
public update() {
// 动画设置
let duration: number = 128;
let progress: number = this.p.frameCount % duration;
if(progress == 0) this.iteration++;
// 行和高度
let numRowsDrawn: number = this.numRows + 1 + this.iteration;
let colW: number = this.p.width / this.numCols;
let rowH: number = this.p.height / this.numRows;
let count = 0;
// 循环遍历行
for (let y: number = this.iteration; y<numRowsDrawn; y++) {
// 计算y位置(从底部开始)
let targetY: number = this.p.height - (y+1) * rowH + this.iteration * rowH;
// 我们在进度中的位置
let posY: number = this.p.map(progress, 0, duration, targetY, targetY+rowH);
// 鼠标影响
const smoothing = 0.06;
this.currentMouseX += (this.p.mouseX - this.currentMouseX) * smoothing;
const mouseInfluence: number = this.p.map(this.currentMouseX, 0, this.p.width, .8, -.3);
// 基于y位置的影响是什么
let yInfluence: number = this.p.map(posY / this.numRows, 0, rowH, 1, this.numRows+1) * mouseInfluence;
// 每行双倍列数
let extraCols: number = Math.exp(yInfluence * Math.LN2);
// 大小和位置
let currentW: number = colW + extraCols * colW;
// 循环遍历列
for (let x:number = 0; x<this.numCols; x++) {
// 计算x位置
let posX: number = x * currentW - (extraCols * yInfluence + 1) * colW;
// 不要绘制超出屏幕x轴的内容
if(posX > this.p.width) continue;
if(posX + currentW < 0) continue;
// 绘制
this.display(x, y, posX, posY, currentW, rowH);
count++;
}
}
}
|
瀑布流网格
我一直喜欢有很多事情发生的灵感网站。你会看到各种图像和视频,它们本身就很强大,但在不同的背景下获得了新的目的。这就是我想要的案例概述。
由于我不追求任何特定的图形风格,我喜欢它更像是一个参考集合。这就是为什么我决定使用瀑布流网格。我不想使用插件,所以我构建了这个小小的CSS/JavaScript东西,我使用CSS Grid行来分布图像,并使用JavaScript来计算它应该跨越多少行,这取决于CMS中设置的宽高比。我认为还有改进的空间,但老实说,我在这方面缺乏耐心。我决定它现在可以胜任。也许有一天我会回过头来重构它。下面是完成大部分工作的代码片段。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
function applyMasonry() {
// 获取网格和项目
const grid = document.querySelector('.masonry-grid');
const items = grid?.querySelectorAll('.masonry-item');
// 确保它们都已加载
if (!grid || !items) return
// 从CSS获取属性
const rowHeight = parseInt(getComputedStyle(grid).getPropertyValue('grid-auto-rows'))
const gap = parseInt(getComputedStyle(grid).getPropertyValue('gap') || 0)
items.forEach(item => {
// 分别获取媒体和信息容器
const media = item.querySelector('.masonry-item__image-container')
const info = item.querySelector('.masonry-item__info-container')
if (!media || !info) return
// 将它们组合成项目高度
const mediaHeight = media.getBoundingClientRect().height
const infoHeight = info.getBoundingClientRect().height
const itemHeight = mediaHeight + infoHeight
// 计算要跨越多少行
const rowSpan = Math.ceil((itemHeight + gap) / (rowHeight + gap))
// 应用行跨度
item.style.gridRowEnd = `span ${rowSpan}`;
item.style.opacity = 1;
})
}
|
P5.js与Three.js对比
为了在Instagram上发布我的标志,我创建了一个Processing草图,将标志放置在像素化的3D场景中旋转。我喜欢它几乎变成了某种雕塑或建筑。现在我只需要构建一个Web版本。
因为我的英雄区域和页脚组件都是p5.js,这是我的首选。但它很慢~我的意思是真的慢。无论我如何尝试优化它,3D工作负载都会降低性能。我几年前只使用过一次Three.js,但我记得它处理3D相当好。不确定通过使用多个库你会拥有性能最好的网站,但既然这一切都只是为了好玩,我决定试一试。使用Three.js版本,我可以向结构添加更多细节,而且与p5.js版本相比,它仍然表现完美。下面你会看到我循环遍历所有体素。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
let instanceId: number = 0;
// 使用体素分辨率(细节)循环,而不是图像分辨率
for (let z: number = 0; z < detail; z++) {
for (let y: number = 0; y < detail; y++) {
const flippedY: number = detail - 1 - y;
for (let x: number = 0; x < detail; x++) {
// 使用归一化坐标采样图像
const sampleX: number = Math.floor((x / detail) * imgDetail);
const sampleY: number = Math.floor((flippedY / detail) * imgDetail);
const sampleZ: number = Math.floor((z / detail) * imgDetail);
const brightness1: number = getBrightnessAt(imgData, imgDetail, sampleX, sampleY);
const brightness2: number = getBrightnessAt(imgData, imgDetail, sampleZ, sampleY);
if (brightness1 < 100 && brightness2 < 100 && instanceId < maxInstances) {
dummy.position.set(
x * cellSize - (detail * cellSize) / 2,
y * cellSize - (detail * cellSize) / 2,
z * cellSize - (detail * cellSize) / 2
);
dummy.updateMatrix();
mesh.setMatrixAt(instanceId, dummy.matrix);
instanceId++;
}
}
}
}
|
资源与代码
由于我真正想鼓励人们开始自己的个人项目之旅,我想分享资源和代码示例来帮助他们开始。
当然,随着这个平台的推出,我不得不为20多个项目追溯性地做这件事,所以未来我可能会分享更多过程和幕后。谁知道呢。无论如何,这个组件为我提供了一个空间,为那些感兴趣的人提供任何可能有用的东西。
总结
这个平台还没有完成~这就是重点。这是一个与我的编码工具互动的空间,是共享草图以供进一步探索的空间,是让过程本身保持可见的空间。如果你是一名设计师或编码员,我希望它能推动你开始或继续自己的副业。这就是创造力保持活力的方式。感谢阅读。