// Based on Flame by:
// Created by anatole duprat - XT95/2013
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
<style>
/* Target Confluence's main content area */
#main-content,
.wiki-content,
.contentLayout2,
.cell,
#content {
position: relative !important;
}
/* Make the background div cover the entire content area */
#flameBackground {
position: absolute !important;
top: 0 !important;
left: 0 !important;
right: 0 !important;
bottom: 0 !important;
width: 100% !important;
height: 100% !important;
z-index: 0 !important;
pointer-events: none !important;
}
#flameCanvas {
width: 100%;
height: 100%;
display: block;
}
/* Ensure actual page content is rendered on top */
.wiki-content > *:not(#flameBackground),
.contentLayout2 > *:not(#flameBackground) {
position: relative;
z-index: 1;
}
/* Text readability */
.wiki-content h1,
.wiki-content h2,
.wiki-content h3,
.wiki-content p {
text-shadow: 0 2px 8px rgba(0,0,0,0.7);
}
</style>
<div id="flameBackground">
<canvas id="flameCanvas"></canvas>
</div>
<script>
(function() {
const canvas = document.getElementById('flameCanvas');
if (!canvas) return;
// Максимальное качество контекста
const gl = canvas.getContext('webgl', {
antialias: true, // Включено сглаживание
alpha: true,
depth: false,
stencil: false,
powerPreference: 'high-performance' // Требуем макс. производительность от GPU
}) || canvas.getContext('experimental-webgl');
if (!gl) return;
const maxSteps = 64; // Максимум шагов для детализации
const resolutionScale = 1.0; // 100% разрешение
const vertexShaderSource = `
attribute vec2 position;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
}
`;
const fragmentShaderSource = `
precision highp float; // Высокая точность вычислений
uniform vec2 iResolution;
uniform float iTime;
uniform int maxSteps;
float noise(vec3 p) {
vec3 i = floor(p);
vec4 a = dot(i, vec3(1., 57., 21.)) + vec4(0., 57., 21., 78.);
vec3 f = cos((p-i)*acos(-1.))*(-.5)+.5;
a = mix(sin(cos(a)*a),sin(cos(1.+a)*(1.+a)), f.x);
a.xy = mix(a.xz, a.yw, f.y);
return mix(a.x, a.y, f.z);
}
float sphere(vec3 p, vec4 spr) {
return length(spr.xyz-p) - spr.w;
}
float flame(vec3 p) {
float d = sphere(p*vec3(1.,.5,1.), vec4(.0,-1.,.0,1.));
return d + (noise(p+vec3(.0,iTime*2.,.0)) + noise(p*3.)*.5)*.25*(p.y);
}
float scene(vec3 p) {
return min(100.-length(p), abs(flame(p)));
}
vec4 raymarch(vec3 org, vec3 dir) {
float d = 0.0, glow = 0.0, eps = 0.02;
vec3 p = org;
bool glowed = false;
// Цикл отрисовки
for(int i=0; i<64; i++) {
if(i >= maxSteps) break;
d = scene(p) + eps;
p += d * dir;
if(d > eps) {
if(flame(p) < .0) glowed = true;
if(glowed) glow = float(i)/float(maxSteps);
}
}
return vec4(p, glow);
}
void main() {
vec2 fragCoord = gl_FragCoord.xy;
vec2 v = -1.0 + 2.0 * fragCoord.xy / iResolution.xy;
v.x *= iResolution.x/iResolution.y;
vec3 org = vec3(0., -2., 14.);
vec3 dir = normalize(vec3(v.x*1.6, -v.y, -1.5));
vec4 p = raymarch(org, dir);
float glow = p.w;
vec4 col = mix(vec4(1.,.5,.1,1.), vec4(0.1,.5,1.,1.), p.y*.02+.4);
gl_FragColor = mix(vec4(0.), col, pow(glow*2., 4.));
}
`;
function compileShader(source, type) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error('Shader compile error:', gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
const vs = compileShader(vertexShaderSource, gl.VERTEX_SHADER);
const fs = compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER);
if (!vs || !fs) return;
const program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error('Program link error:', gl.getProgramInfoLog(program));
return;
}
gl.useProgram(program);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1,1,-1,-1,1,1,1]), gl.STATIC_DRAW);
const pos = gl.getAttribLocation(program, 'position');
gl.enableVertexAttribArray(pos);
gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 0, 0);
const iRes = gl.getUniformLocation(program, 'iResolution');
const iTime = gl.getUniformLocation(program, 'iTime');
const maxStepsUniform = gl.getUniformLocation(program, 'maxSteps');
gl.uniform1i(maxStepsUniform, maxSteps);
function resize() {
const container = canvas.parentElement;
if (!container) return;
const rect = container.getBoundingClientRect();
const displayWidth = rect.width || window.innerWidth;
const displayHeight = rect.height || window.innerHeight;
// Установка полного разрешения без масштабирования
canvas.width = Math.floor(displayWidth * resolutionScale);
canvas.height = Math.floor(displayHeight * resolutionScale);
gl.viewport(0, 0, canvas.width, canvas.height);
}
// Вставка фона в контент
setTimeout(function() {
const bg = document.getElementById('flameBackground');
const content = document.querySelector('.wiki-content') ||
document.querySelector('#main-content') ||
document.querySelector('.contentLayout2') ||
document.querySelector('#content');
if (content && bg) {
content.insertBefore(bg, content.firstChild);
resize();
}
}, 100);
window.addEventListener('resize', resize);
const start = Date.now();
let animationId = null;
let isPageVisible = true;
// Остановка только если вкладка полностью скрыта (стандарт браузера)
document.addEventListener('visibilitychange', function() {
isPageVisible = !document.hidden;
if (isPageVisible && !animationId) {
animationId = requestAnimationFrame(render);
}
});
function render() {
if (!isPageVisible || gl.isContextLost()) {
animationId = null;
return;
}
// Рендер без ограничения FPS - максимальная плавность
gl.uniform2f(iRes, canvas.width, canvas.height);
gl.uniform1f(iTime, (Date.now() - start) / 1000);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
animationId = requestAnimationFrame(render);
}
animationId = requestAnimationFrame(render);
// Очистка при удалении элемента
if (window.MutationObserver) {
const observer = new MutationObserver(function(mutations) {
if (!document.body.contains(canvas)) {
if (animationId) {
cancelAnimationFrame(animationId);
animationId = null;
}
observer.disconnect();
}
});
observer.observe(document.body, { childList: true, subtree: true });
}
})();
</script> |
Если станет холодно на просторах вселенной - наш огонь согреет.
。゚•┈୨♡୧┈•゚。
。゚•┈୨♡୧┈•゚。
。゚•┈୨♡୧┈•゚。
。゚•┈୨♡୧┈•゚。
。゚•┈୨♡୧┈•゚。
。゚•┈୨♡୧┈•゚。
。゚•┈୨♡୧┈•゚。
。゚•┈୨♡୧┈•゚。。゚•┈୨♡୧┈•゚。。゚•┈୨♡୧┈•゚。
。゚•┈୨♡୧┈•゚。。゚•┈୨♡୧┈•゚。。゚•┈୨♡୧┈•゚。
。゚•┈୨♡୧┈•゚。。゚•┈୨♡୧┈•゚。。゚•┈୨♡୧┈•゚。
。゚•┈୨♡୧┈•゚。。゚•┈୨♡୧┈•゚。。゚•┈୨♡୧┈•゚。
。゚•┈୨♡୧┈•゚。。゚•┈୨♡୧┈•゚。。゚•┈୨♡୧┈•゚。
。゚•┈୨♡୧┈•゚。
。゚•┈୨♡୧┈•゚。
。゚•┈୨♡୧┈•゚。
。゚•┈୨♡୧┈•゚。
。゚•┈୨♡୧┈•゚。
。゚•┈୨♡୧┈•゚。
。゚•┈୨♡୧┈•゚。