Wallpapers para Windows
O PrimoEngine também roda no Windows 11 (23H2 ou mais novo, PCs x64 e ARM64). O formato é o
mesmo .livewallpaper v1: um ZIP com manifest.json + content/. A versão para Windows já saiu, em
beta: baixe em https://engine.oprimo.dev.
Resumo: wallpapers web e vídeo funcionam nos dois sistemas com o mesmo arquivo. Shader
é um pacote por sistema: metal no Mac, hlsl no Windows.
| Tipo | Mac | Windows |
|---|---|---|
web | ✅ | ✅ o mesmo arquivo, a mesma API window.LiveWallpaper |
video | ✅ | ✅ o mesmo arquivo (Premium nos dois) |
metal | ✅ | ❌ recusado: This wallpaper was made for Mac (Metal shader). Look for its Windows version. |
hlsl | ❌ (o Mac não conhece o tipo e recusa o manifest) | ✅ |
minMacOS é ignorado no Windows.
Shader no Windows: o tipo hlsl
Um pacote hlsl é o gêmeo de um pacote metal: mesmo id, mesmo config, outro entry. Com
o mesmo id, o app trata os dois como o mesmo wallpaper, e os ajustes têm os mesmos nomes. Para
compartilhar, mande dois arquivos, por exemplo aurora-mac.livewallpaper e
aurora-windows.livewallpaper.
manifest.json:
{
"schemaVersion": 1,
"id": "com.example.hello-shader",
"version": "1.0.0",
"title": "Hello Shader",
"author": { "handle": "@you" },
"type": "hlsl",
"entry": "content/shader.hlsl",
"config": [
{ "key": "speed", "type": "float", "min": 0.1, "max": 3.0, "default": 1.0, "label": "Speed" },
{ "key": "tint", "type": "color", "default": "#FFFFFF", "label": "Tint" }
],
"capabilities": { "network": [] }
}
content/shader.hlsl (é o hello-shader em HLSL; baixe pronto em
hello-shader-windows):
// Contrato com o PrimoEngine: mantenha esta struct como está (32 bytes, register b0).
struct Uniforms {
float2 resolution; // tamanho da tela em pixels
float time; // segundos desde que o wallpaper começou
float speed; // ajuste "speed" (padrão 1.0)
float4 tint; // ajuste "tint" em RGB 0..1 (a = 1)
};
cbuffer PrimoUniforms : register(b0) { Uniforms u; };
// Obrigatório: a função de pixel, com o nome exato f_main.
float4 f_main(float4 fragCoord : SV_Position) : SV_Target {
float2 uv = fragCoord.xy / u.resolution; // 0..1, origem no canto superior esquerdo
float t = u.time * u.speed;
float v = sin(uv.x * 8.0 + t) + sin(uv.y * 6.0 - t * 0.7)
+ sin(length(uv - 0.5) * 14.0 - t * 1.3);
float3 col = 0.5 + 0.5 * cos(6.28318 * (v * 0.2 + float3(0.0, 0.33, 0.67)));
return float4(col * u.tint.rgb, 1.0);
}
O contrato
- O app compila o shader com o FXC como
ps_5_0(Direct3D 11), na importação. - Só a função de pixel. Não existe
v_main: o app desenha o triângulo de tela cheia. - Entrada
f_main, comSV_Position(pixels, origem no canto superior esquerdo, igual ao[[position]]do Metal) e uma saídafloat4emSV_Target. Devolva as mesmas cores que o gêmeo Metal devolve. - Uniforms em
register(b0), no máximo 240 bytes. Declarar só os primeiros 32 bytes (a struct acima) é o normal. Os ajustes chegam ao shader do mesmo jeito que no Mac. - Opcional: um
SamplerStateemregister(s0)(linear, clamp). - Sem
#include: não há como incluir outro arquivo. - Um shader que entra em loop infinito trava a GPU por ~2 s; o Windows reinicia o driver e o PrimoEngine põe o wallpaper de quarentena. Mantenha os loops curtos (~64 iterações por pixel).
Shaders que reagem à música
Com "capabilities": { "audioReactive": true }, o shader recebe um resumo do som que o PC está
tocando, nunca o áudio em si. Os valores são os mesmos do Mac (veja
Shaders que reagem ao som); só o layout muda,
porque o HLSL alinha arrays a 16 bytes:
struct AudioUniforms {
float4 bands4[8]; // banda i = bands4[i >> 2][i & 3], 32 bandas de 30 Hz a 16 kHz, 0..1
float4 levels; // x graves, y médios, z agudos, w nível geral
float beat, bassTime, levelTime, midTime;
float4 beatAges; // segundos desde as 4 últimas batidas, mais nova primeiro; 9 = nenhuma
float active; // vai a 0 depois de ~2 s de silêncio
};
cbuffer PrimoAudio : register(b1) { AudioUniforms audio; };
Texture2D<float4> history : register(t0); // opcional: 32 × 64, canal r, linha 0 = agora
float band(int i) { return audio.bands4[i >> 2][i & 3]; }
Leia o histórico com history.Load(int3(banda, linha, 0)).r. Sem música (e nas miniaturas), tudo
vale 0 e beatAges vale 9: desenhe um visual parado bonito.
Do Metal para o HLSL
| Metal | HLSL |
|---|---|
#include <metal_stdlib>, using namespace metal;, v_main | apague |
fragment float4 f_main(float4 p [[position]], constant Uniforms& u [[buffer(0)]]) | cbuffer PrimoUniforms : register(b0) { Uniforms u; }; e float4 f_main(float4 p : SV_Position) : SV_Target |
constant AudioUniforms& audio [[buffer(1)]], audio.bands[i] | cbuffer PrimoAudio : register(b1), audio.bands4[i >> 2][i & 3] |
texture2d<float> history [[texture(0)]], history.read(uint2(x, y)).r | Texture2D<float4> history : register(t0), history.Load(int3(x, y, 0)).r |
fract, mix, rsqrt, atan2(y, x) | frac, lerp, rsqrt, atan2(y, x) |
fmod(x, y) | fmod(x, y) (igual; o mod do GLSL é x - y * floor(x / y)) |
float2x2 m; m * v | mul(v, m), com o mesmo construtor: a ordem do produto inverte |
float3(1.0) | float3(1.0, 1.0, 1.0) ou (float3)1.0 |
Confira o resultado lado a lado com o Mac: as cores e o movimento devem ser os mesmos.
O que o Windows recusa na importação
O app compila e inspeciona todo shader hlsl ao importar, venha de onde vier:
| Mensagem | O que fazer |
|---|---|
Shader is missing the required 'f_main' fragment function. | Dê o nome f_main à função de pixel. |
Shader didn't compile: … | Corrija o erro mostrado. #include sempre falha. |
Shader rejected: the source is larger than 512 KB. | Diminua o arquivo. |
Shader rejected: … writable … | Tire recursos de escrita (RWTexture2D, RWBuffer, buffers estruturados, atômicos). |
Shader reads audio (register(b1)) but the manifest doesn't declare … | Adicione "capabilities": { "audioReactive": true }, ou tire o b1. |
Shader rejected: '…' is bound outside … | Use só b0, b1, t0 e s0. |
Shader rejected: the uniforms … are larger than … | b0 vai até 240 bytes e b1 até 192. |
Nomes de arquivo
O Windows recusa nomes que o Mac aceita, com Corrupt archive: unsafe path ’…’. Evite em qualquer pacote que deva rodar nos dois:
\e:em qualquer lugar, e< > " | ? *;- pastas vazias no caminho (
a//b) e nomes que terminam em.ou espaço; CON,PRN,AUX,NUL,COM1aCOM9,LPT1aLPT9como nome, com ou sem extensão (por exemplocontent/nul.txt).
Empacotar e testar
python3 pack.py <pasta> aceita type: "hlsl": confere o manifest, o f_main, os registros e os
recursos proibidos, e gera o .livewallpaper. Ele não compila o HLSL; quem compila é o app, ao
importar. No PrimoEngine para Windows, importe pelo botão Importar ou com dois cliques no arquivo.
No Windows o Python não vem instalado: instale o Python 3 pela Microsoft Store (ou em python.org) e
rode py pack.py <pasta>.
Para gerar com IA, use o prompt de shader HLSL.