RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 924210
Accepted
Alexandr_TT
Alexandr_TT
Asked:2020-12-23 00:38:08 +0000 UTC2020-12-23 00:38:08 +0000 UTC 2020-12-23 00:38:08 +0000 UTC

圣诞树动画

  • 772

新年快到了!

让自己和他人振作起来会很好。复制和发送带有从网络下载的精美图片和 GIF 的明信片不知何故不再有趣。

我想要一些不寻常的、明亮的、喜庆的东西,只有你拥有,你可以用这样的话送给你所爱的人——“我为你做的!”
或者带着满足感和自豪感离开它:-)

制作新年动画比赛的想法属于@Hamster

这是她作为样本提供的图纸。

在此处输入图像描述

看,就像在任何其他新年贺卡中一样,各种动画都有潜力。

例如:

  • 来自星星的光线。

stroke-dasharray使用宽字符串可以轻松完成。添加径向渐变、线旋转动画和渐变移动。

  • 雪花

要在 CSS 或 SVG 中绘制,许多人将能够进一步为雪花的大小、旋转和下落设置动画。

  • 花环的人字形
    眨眼,圣诞树装饰物、烟火等的光摇摆和扭动等。
  • 短语动画 - 2019 年新年快乐!

    短语移动和/或摆动、笔划、字母外观

  • 新年人物动画 - 松鼠、兔子 :) 圣诞老人和雪少女

您可以执行上面列出的整个动画列表,您可以实现一项或多项。

主要条件是你可以拍任何照片或自己画,但动画应该是你自己的,不能复制粘贴!

比赛已经结束。

祝贺获胜者@Misha Saidov

感谢您的作品,亲爱的参与者,比赛变得有趣、明亮和令人难忘。我们一起了解了新参与者的名字,他们立即在移动中闯入竞争并做出了非常酷的工作。
所有作品都是在高水平上完成的,每件作品都以自己的方式有趣和优秀。

javascript
  • 18 18 个回答
  • 10 Views

18 个回答

  • Voted
  1. Misha Saidov
    2020-12-23T23:24:01Z2020-12-23T23:24:01Z

    Это бандл из моих предыдущих ответов.

    Как видите, код стал модульным - можно на его базе собрать любого Франкенштейна. Также код вариативный везде, где только можно - любой коэффициент можно поменять, чтобы добиться желаемого результата и резиновый (на сколько смог). Повторюсь, что я не умею в векторную графику и канвас, поэтому накодил все на дивах и картинках. Разверните на всю страницу, если сильно сплющит.

    UPD 0: Добавил покачивание снежинок, изменил некоторые коэффициенты и сменил изображение звездочек елки на более нейтральное.

    UPD 1: Добавил текст и заанимировал.

    UPD 2: Санта! Он будет появляться и махать рукой с разных сторон экрана. Думаю, далее будут только какие-то минорные правки, а так - это финалочка ;)

    UPD 3: Оптимизация. Теперь все делает один цикл (вместо 4-х, как раньше). Открытка стала чуть более снисходительна на старт: картинки появляются только после полной загрузки и убрал ненужный тут $(document).ready() Скрипт по-прежнему костыль :)

    const randomBetween = (a, b) => {
      return (a + (Math.random() * (b - a)));
    }
    const randomArr = (arr) => {
      return arr[Math.round(Math.random() * (arr.length - 1))];
    }
    
    const params = {
      snowflakes: {
        amount: 15,
        duration: {
          min: 3,
          max: 8
        },
        size: {
          min: 10,
          max: 32
        },
        src: [
          "http://pngimg.com/uploads/snowflakes/snowflakes_PNG7578.png",
          "https://vignette.wikia.nocookie.net/fantendo/images/2/27/Snowflake.png/revision/latest?cb=20121220012520",
          "https://latxikadelacerveza.es/wp-content/plugins/christmas-panda/assets/images/snowflake_5.png"
        ],
        container: "#snowflakes"
      },
      tree: {
        amount: 300,
        stretching: 1.4,
        movement: 5,
        src: "https://i.imgur.com/pPjPR8q.png",
        duration: {
          min: 5,
          max: 50
        },
        size: {
          min: 20,
          max: 30
        },
        container: "#tree"
      },
      rays: {
        amount: 40,
        duration: 30,
        width: 3,
        height: 100,
        perspective: 150,
        color: "rgba(215,249,111,1)",
        container: "#rays"
      },
      text: {
        text: "С Новым 2019 годом!",
        duration: 30,
        width: 3,
        height: 100,
        perspective: 150,
        color: "rgba(215,249,111,1)",
        container: "#text"
      }
    }
    
    
    let totalAmount = 0;
    for (let key in params) {
      let amount = params[key].amount;
      totalAmount += typeof amount === "number" ? amount : 0;
    }
    
    for (let i = 0; i < totalAmount; i++) {
      if (i < params.snowflakes.amount) {
        let snowflake = $("<img src='" + randomArr(params.snowflakes.src) + "'>");
        let randomSize = randomBetween(params.snowflakes.size.min, params.snowflakes.size.max);
        snowflake.css({
          "width": randomSize + "px",
          "height": randomSize + "px",
          "left": randomBetween(0, 100) + "%",
          "animation-duration": randomBetween(params.snowflakes.duration.min, params.snowflakes.duration.max) + "s"
        });
    
        $(params.snowflakes.container).append(snowflake);
      }
    
    
    
      if (i < params.tree.amount) {
        if (i === 0) {
          $(params.tree.container).append("<img class='main' src='" + params.tree.src + "'>");
        }
        let star = $("<img src='" + params.tree.src + "'>");
        let top = randomBetween(0, randomBetween(70, 100));
        let randomSize = (randomBetween(params.tree.size.min, params.tree.size.max) * (top + 10) / 100);
        star.css({
          "width": randomSize + "px",
          "height": randomSize + "px",
          "left": "calc(50% - " + (Math.sin(top / params.tree.stretching) * top) + "px)",
          "top": top + "%",
          "animation-duration": randomBetween(params.tree.duration.min, params.tree.duration.max) + "s",
          "transform-origin": (50 + randomBetween(-params.tree.movement, params.tree.movement)) + "% " + (50 + randomBetween(-params.tree.movement, params.tree.movement)) + "%"
        });
    
        $(params.tree.container).append(star);
      }
    
    
    
      if (i < params.rays.amount) {
        if (i === 0) {
          $(params.rays.container).css({
            "animation-duration": params.rays.duration + "s",
            width: params.rays.height * 2 + "px",
            height: params.rays.height * 2 + "px"
          });
          window.alignRays = () => {
            let mainStar = $(params.tree.container).find(".main");
            $(params.rays.container).css("top", (mainStar.offset().top - params.rays.height) + (mainStar.height() / 2) + "px");
          }
          $(window).on("resize", window.alignRays);
        }
        let ray = $("<div></div>");
        ray.css({
          "width": params.rays.width + "px",
          "height": params.rays.height + "px",
          "transform": "perspective(" + params.rays.perspective + "px) rotateZ(" + (360 / params.rays.amount * i) + "deg) rotateX(-60deg)",
          "background": "linear-gradient(to bottom, rgba(0,0,0,0) 0%," + params.rays.color + " 100%)"
        });
    
        $(params.rays.container).append(ray);
      }
    
    
    
      if (i < params.text.text.length) {
        let char = params.text.text.substr(i, 1);
        char = char === " " ? "&nbsp;" : char;
        let charElem = $("<div>" + char + "</div>");
        charElem.css("animation-delay", (i / 10) + "s");
        $(params.text.container).append(charElem);
      }
    
    
    
      if (i === totalAmount - 1) {
        $("#root").css("display", "block");
        window.alignRays();
        let selector = [];
        for (let key in params) {
          let container = params[key].container;
          selector.push(typeof container === "string" ? container + " > img" : "");
        }
        selector = selector.join(",");
        $(selector).css("display", "none");
        $(selector).on("load", (e) => $(e.target).css("display", ""));
      }
    }
    
    
    let santa = $("#santa");
    santa.css("display", "none");
    santa.on("load", (e) => $(e.target).css("display", ""));
    setInterval(() => {
      let side = ["right", "left"][Math.round(Math.random())];
      let randTop = Math.round(Math.random() * ($(window).height() - 220));
      santa.css("top", randTop + "px");
      santa.addClass(side);
      setTimeout(() => {
        santa.removeClass();
      }, 2000);
    }, 4000);
    body,
    html {
      margin: 0;
      width: 100%;
      height: 100%;
      background: radial-gradient(ellipse at 50% 30%, #a1c920 10%, #1e2708 100%);
      overflow: hidden;
    }
    
    #root {
      position: absolute;
      width: 100%;
      height: 100%;
      overflow: hidden;
      display: none;
    }
    
    #santa {
      position: absolute;
      display: none;
      z-index: 12;
      top: 20px;
      width: 135px;
      animation-duration: 2s;
      transform-origin: bottom;
      animation-timing-function: linear;
    }
    
    #santa.left {
      animation-name: santa-left;
      display: block;
      left: -135px;
    }
    
    #santa.right {
      animation-name: santa-right;
      display: block;
      right: -135px;
    }
    
    #text {
      position: absolute;
      bottom: 8%;
      left: 0;
      right: 0;
      margin: 0 auto;
      z-index: 11;
      width: 390px;
      white-space: nowrap;
    }
    
    #text>div {
      position: relative;
      display: inline-block;
      float: left;
      font-size: 40px;
      font-family: Pacifico;
      animation-name: text;
      animation-iteration-count: infinite;
      transform-origin: center center;
      animation-timing-function: linear;
      animation-duration: 4s;
      color: white;
      opacity: 0;
      text-shadow: 0 0 10px yellow;
    }
    
    #rays {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      margin: 0 auto;
      border-radius: 100%;
      z-index: 8;
      animation-name: rotate;
      transform-origin: center center;
      animation-iteration-count: infinite;
      animation-timing-function: linear;
      background: radial-gradient(circle, rgba(0, 0, 0, 0.2) 0%, rgba(0, 212, 255, 0) 70%);
    }
    
    #rays>div {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      margin: 0 auto;
      transform-origin: center bottom;
    }
    
    #snowflakes {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      z-index: 7;
    }
    
    #snowflakes>img {
      position: absolute;
      animation-name: drop;
      transform-origin: top center;
      animation-iteration-count: infinite;
      animation-timing-function: linear;
    }
    
    #tree {
      position: absolute;
      top: 20%;
      left: 0;
      right: 0;
      bottom: 0;
      margin: 0 auto;
      width: 200px;
      height: 270px;
      z-index: 9;
    }
    
    #tree>img.main {
      position: absolute;
      top: -10px;
      left: 0;
      right: 0;
      margin: 0 auto;
      width: 35px;
      height: 35px;
      z-index: 1;
      animation-duration: 20s;
      animation-name: rotate;
      transform-origin: center center;
      animation-iteration-count: infinite;
      animation-timing-function: linear;
    }
    
    #tree>img {
      position: absolute;
      animation-name: shake;
      transform-origin: center center;
      animation-iteration-count: infinite;
      animation-timing-function: ease-in-out;
    }
    
    @keyframes drop {
      0% {
        top: 0%;
        opacity: 0;
        transform: rotate(0deg);
      }
      20%,
      80% {
        opacity: .7;
      }
      50% {
        opacity: .5;
      }
      100% {
        top: 100%;
        opacity: 0;
        transform: rotate(360deg);
      }
    }
    
    @keyframes rotate {
      0% {
        transform: rotate(0deg);
      }
      100% {
        transform: rotate(360deg);
      }
    }
    
    @keyframes text {
      0% {
        transform: rotate(-20deg) scale(0);
        opacity: 0;
      }
      10% {
        transform: rotate(10deg) scale(1.1);
        opacity: 1;
      }
      20% {
        transform: rotate(-5deg) scale(.9);
        opacity: 1;
      }
      30% {
        transform: rotate(0deg) scale(1);
        opacity: 1;
      }
      80% {
        transform: scale(1);
        opacity: 1;
      }
      90% {
        transform: scale(2);
        opacity: 0;
      }
      100% {
        transform: rotate(0deg) scale(1);
        opacity: 0;
      }
    }
    
    @keyframes shake {
      0%,
      100% {
        transform: rotate(0deg) scale(1);
        opacity: .4;
      }
      10% {
        transform: rotate(50deg) scale(.5);
        opacity: .6;
      }
      20% {
        transform: rotate(180deg) scale(.7);
        opacity: .7;
      }
      30% {
        transform: rotate(150deg) scale(1);
        opacity: .4;
      }
      40% {
        transform: rotate(130deg) scale(.6);
        opacity: .8;
      }
      50% {
        transform: rotate(60deg) scale(0);
        opacity: 1;
      }
      60% {
        transform: rotate(120deg) scale(.4);
        opacity: .8;
      }
      70% {
        transform: rotate(300deg) scale(.1);
        opacity: .7;
      }
      80% {
        transform: rotate(240deg) scale(.5);
        opacity: .6;
      }
      90% {
        transform: rotate(200deg) scale(.9);
        opacity: .3;
      }
    }
    
    @keyframes santa-right {
      from,
      to {
        transform: translate3d(0, 0, 0);
      }
      10%,
      30%,
      50%,
      70%,
      90% {
        transform: rotate(-75deg);
      }
      20%,
      40%,
      60%,
      80% {
        transform: rotate(-65deg);
      }
      0%,
      100% {
        transform: rotate(0deg);
      }
    }
    
    .santa-right {
      animation-name: santa-right;
    }
    
    @keyframes santa-left {
      10%,
      30%,
      50%,
      70%,
      90% {
        transform: rotate(75deg);
      }
      20%,
      40%,
      60%,
      80% {
        -webkit-transform: rotate(65deg);
        transform: rotate(65deg);
      }
      0%,
      100% {
        transform: rotate(0deg);
      }
    }
    
    .santa-left {
      -webkit-animation-name: santa-left;
      animation-name: santa-left;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <link href="https://fonts.googleapis.com/css?family=Pacifico" rel="stylesheet">
    
    <div id="root">
      <div id="tree"></div>
      <div id="snowflakes"></div>
      <div id="rays"></div>
      <div id="text"></div>
      <img id="santa" class="right" src="https://i.imgur.com/Fyyiz3d.png">
    </div>

    • 60
  2. Stranger in the Q
    2020-12-30T07:43:23Z2020-12-30T07:43:23Z

    Новогодняя сценка создана без использования каких-либо ресурсов.

    ОТСТОРОЖНО, сниппет может вызвать странные эффекты, тут процессор почти ничем не занят, весь алгоритм реализован во фрагментном шейдере и если у Вас нет видеокарты то извиняйте...

    在此处输入图像描述

    <script>
        var fragCode =`
        
    precision highp float;
    
    uniform vec2 resolution;
    uniform vec3 eye;
    uniform vec3 lightPos;
    uniform float time;
    
    // https://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
    // distance functions
    
    float dot2( in vec2 v ) {
        return dot(v,v);
    }
    
    float sdCappedCone( in vec3 p, in float h, in float r1, in float r2 ){
        vec2 q = vec2( length(p.xz), p.y );
        vec2 k1 = vec2(r2,h);
        vec2 k2 = vec2(r2-r1,2.0*h);
        vec2 ca = vec2(q.x-min(q.x,(q.y < 0.0)?r1:r2), abs(q.y)-h);
        vec2 cb = q - k1 + k2*clamp( dot(k1-q,k2)/dot2(k2), 0.0, 1.0 );
        float s = (cb.x < 0.0 && ca.y < 0.0) ? -1.0 : 1.0;
        return s*sqrt( min(dot2(ca),dot2(cb)) );
    }
    
    // vertical
    float sdCylinder( vec3 p, vec2 h ){
      vec2 d = abs(vec2(length(p.xz),p.y)) - h;
      return min(max(d.x,d.y),0.0) + length(max(d,0.0));
    }
    
    float sdSphere( vec3 p, float s ){
        return length(p)-s;
    }
    
    float sdPlane( vec3 p , float down){
    	return p.y - down;
    }
    
    float plane(vec3 p, vec3 n, float offs) {
        return dot(p, n) - offs;
    }
    
    
    // distance functions operations
    
    float opS( float d1, float d2 ){
        return max(-d2,d1);
    }
    
    vec2 opU( vec2 d1, vec2 d2 ){
    	return (d1.x<d2.x) ? d1 : d2;
    }
    
    vec3 opRep( vec3 p, vec3 c ){
        return mod(p,c)-0.5*c;
    }
    
    float opSmoothU( float d1, float d2, float k ) {
        float h = clamp( 0.5 + 0.5*(d2-d1)/k, 0.0, 1.0 );
        return mix( d2, d1, h ) - k*h*(1.0-h);
    }
    
    vec2 rotate(vec2 p, float ang) {
        float c = cos(ang), s = sin(ang);
        return vec2(p.x*c - p.y*s, p.x*s + p.y*c);
    }
    
    vec2 repeatAng(vec2 p, float n) {
        float ang = 2.0*3.14/n;
        float sector = floor(atan(p.x, p.y)/ang + 0.5);
        p = rotate(p, sector*ang);
        return p;
    }
    
    ///
    
    const float PI =3.141592;
    const float PI2 = 6.2831853;
    
    const float maxd = 256.0; //Max depth
    float nearestD = maxd;
    vec3 color = vec3(0.0, 0.0, 1.0);
    
    float flakes(vec3 p) {
    
        const float snowflakeMaxDist = 20.0;
        if ( (abs(p.x) > snowflakeMaxDist) ||
             (abs(p.y) > snowflakeMaxDist) ||
             (abs(p.z) > snowflakeMaxDist) )
    
             return 9999.9;
    
        float snowPush = 0.25*time;
    
        p.x += snowPush*-3.0;
        p.y += snowPush*1.5;
        p.z += snowPush*-0.25;
    
        const float modDist = 2.0;
    
        float stepX = floor(p.x/modDist);
        float stepY = floor(p.y/modDist);
        float stepZ = floor(p.z/modDist);
    
        vec3 flakeP = vec3(
            mod(p.x,modDist),
            mod(p.y,modDist),
            mod(p.z,modDist)
        );
    
        vec3 flakePos = vec3(modDist*0.5);
        flakePos.x += sin(snowPush+stepY*1.0)*(2.0/5.0)*modDist;
        flakePos.y += sin(snowPush+stepZ*1.3)*(2.0/5.0)*modDist;
        flakePos.z += sin(snowPush+stepX*1.7)*(2.0/5.0)*modDist;
        return sdSphere(flakeP- flakePos, 0.03);
    }
    
    // noise
    float hash(vec3 p) {
        p  = fract( p*0.3183099+.1 );
    	p *= 17.0;
        return fract( p.x*p.y*p.z*(p.x+p.y+p.z) );
    }
    float noise( in vec3 x ){
        vec3 p = floor(x);
        vec3 f = fract(x);
        f = f*f*(3.0-2.0*f);
        return mix(mix(mix( hash(p+vec3(0,0,0)),
                            hash(p+vec3(1,0,0)),f.x),
                       mix( hash(p+vec3(0,1,0)),
                            hash(p+vec3(1,1,0)),f.x),f.y),
                   mix(mix( hash(p+vec3(0,0,1)),
                            hash(p+vec3(1,0,1)),f.x),
                       mix( hash(p+vec3(0,1,1)),
                            hash(p+vec3(1,1,1)),f.x),f.y),f.z);
    }
    
    float noise( vec2 x ){
        return noise(vec3(x, 0.));
    }
    
    const float VERY_FAR = 1e11;
    
    float ground(vec3 p){
        float d = -0.50 ;
        p.y += noise(p)*.33 ;
        d = sdPlane(p, d);
        return d;
    }
    
    vec2 star(vec3 p) {
        p.y -=1.5;
        p.xy = repeatAng(p.xy, 5.0);            // 3. Clone five cornders radially about Z axis
        p.xz = abs(p.xz);                       // 2. Symmetrical about XoY and ZoY
        vec3 n = vec3(0.5, 0.25, 0.8);
        float d = plane(p, normalize(n), 0.065);  // 1. A plane cutting the corner of X+Y+Z+
        return vec2(d, .900 );
    }
    
    vec2 green(vec3 p) {
        float d = VERY_FAR;
        float k = .12;
        d =              sdCappedCone( p - vec3(.0, .99, .0), .4, 0.45, .0);
        d = opSmoothU(d, sdCappedCone( p - vec3(.0, .55, .0), .5, 0.55, .0), k);
        d = opSmoothU(d, sdCappedCone( p - vec3(.0, .11, .0), .6, 0.65, .0), k);
        return vec2( d, 0.090 );
    }
    
    vec2 trunk(vec3 p) {
        float d = VERY_FAR;
        d = sdCylinder(p-vec3(.0, -.5,.0), vec2(0.1, 0.6));
        return vec2( d, 0.000 );
    }
    
    vec2 toy(vec3 p, float col) {
        float d = VERY_FAR;
        d = sdSphere(p, 0.07);
        return vec2( d, col );
    }
    
    vec2 toys(vec3 p) {
        vec2 res = vec2(VERY_FAR, -1);
    
        float r = .42;
        float h = -0.57;
        res = opU( res, toy(p-vec3(-r, h, -r), 0.990) );
        res = opU( res, toy(p-vec3(-r, h,  r), 0.099) );
        res = opU( res, toy(p-vec3( r, h, -r), 0.999) );
        res = opU( res, toy(p-vec3( r, h,  r), 0.555) );
    
        r = .3;
        h = 0.5;
        res = opU( res, toy(p-vec3(-r, h, -r), 0.990) );
        res = opU( res, toy(p-vec3(-r, h,  r), 0.099) );
        res = opU( res, toy(p-vec3( r, h, -r), 0.999) );
        res = opU( res, toy(p-vec3( r, h,  r), 0.555) );
    
        r = .5;
        h = -0.05;
        res = opU( res, toy(p-vec3(-r, h, 0.), 0.990) );
        res = opU( res, toy(p-vec3( 0, h, -r), 0.099) );
        res = opU( res, toy(p-vec3( r, h, 0.), 0.999) );
        res = opU( res, toy(p-vec3( 0, h, r), 0.555) );
    
        return res;
    }
    
    
    vec2 tree(vec3 p) {
        vec2 res = vec2(VERY_FAR, -1);
    
        res = opU( res, green(p) );
        res = opU( res, trunk(p) );
        res = opU( res, star(p) );
        res = opU( res, toys(p) );
    
        return res;
    }
    
    float snowmans(vec3 p) {
    
        // mirror 3
        p.xz = repeatAng(p.xz, 3.0);
        p.xz = abs(p.xz);
    
        float k = .12;
        float d =        sdSphere( p - vec3(1.5,  0.7, 3.0), .2);
        d = opSmoothU(d, sdSphere( p - vec3(1.5,  0.2, 3.0), .3), k);
        d = opSmoothU(d, sdSphere( p - vec3(1.5, -0.4, 3.0), .4), k);
        return d;
    }
    
    float snowfall(vec3 p) {
        vec3 q = vec3(mod(p.x, 3.0) - 1.5, p.yz);
        return sdSphere( q - vec3(1.5,  0.7, 3.0), .02);
    }
    
    vec2 snow(vec3 p) {
    
        float k = .12;
        float d = ground(p);
        d = opSmoothU(d, snowmans( p ), k);
        d = opSmoothU( d, flakes(p), k );
        return vec2( d, .999 );
    }
    
    vec2 snowmans_accesories(vec3 p) {
    
        // mirror 3
        p.xz = repeatAng(p.xz, 3.0);
        p.xz = abs(p.xz);
    
        float k = .12;
        vec2 res =     vec2(sdSphere( p - vec3(1.50,  0.70, 3.20), .02), 0.00 );
        res = opU(res, vec2(sdSphere( p - vec3(1.44,  0.75, 3.18), .02), 0.00 ));
        res = opU(res, vec2(sdSphere( p - vec3(1.56,  0.75, 3.18), .02), 0.00 ));
        res = opU(res, vec2(sdSphere( p - vec3(1.50,  0.25, 3.30), .02), 0.00 ));
        res = opU(res, vec2(sdSphere( p - vec3(1.50, -0.40, 3.40), .02), 0.00 ));
        return res;
    }
    
    
    vec2 map(vec3 p) {
        vec2 res = vec2(VERY_FAR, -1);
    
        res = opU( res, snow(p) );
        res = opU( res, snowmans_accesories(p) );
        res = opU( res, tree(p) );
    
    
        return res;
    }
    
    // ray direction
    
    vec3 rayDirection(float fieldOfView, vec2 size) {
        vec2 xy = gl_FragCoord.xy - size / 2.0;
        float z = size.y / tan(radians(fieldOfView) / 2.0);
        return normalize(vec3(xy, -z));
    }
    
    
    // compute view matrix
    
    mat4 viewMatrix(vec3 eye, vec3 center, vec3 up) {
    	vec3 f = normalize(center - eye);
    	vec3 s = normalize(cross(f, up));
    	vec3 u = cross(s, f);
    	return mat4(
    		vec4(s, 0.0),
    		vec4(u, 0.0),
    		vec4(-f, 0.0),
    		vec4(0.0, 0.0, 0.0, 1)
    	);
    }
    
    
    // ro - ray origin
    // rd - ray direction
    vec2 castRay( in vec3 ro, in vec3 rd ) {
    
        float tmin = 1.0;
        float tmax = 32.0;
        float t = tmin;
        float m = -1.0;
    
        for ( int i=0; i<128; i++ ) {
    	    float precis = 0.0001*t;
    	    vec2 res = map( ro+rd*t );
            if ( res.x<precis || t>tmax )
                break;
            t += res.x/1.4;
    	    m = res.y;
        }
    
        if ( t>tmax )
            m=-1.0;
    
        return vec2( t, m );
    }
    
    // estimate normal at point
    // http://iquilezles.org/www/articles/normalsSDF/normalsSDF.htm
    
    const float NORMAL_EPSILON = 0.0005;
    
    vec3 estimateNormal(vec3 pos) {
        vec2 e = vec2(1.0,-1.0)*0.5773*NORMAL_EPSILON;
        return normalize( e.xyy*map( pos + e.xyy ).x +
    					  e.yyx*map( pos + e.yyx ).x +
    					  e.yxy*map( pos + e.yxy ).x +
    					  e.xxx*map( pos + e.xxx ).x );
    }
    
    
    const vec3 K_a = vec3(.3, .2, .2);
    const vec3 K_d = vec3(.2, .4, .7);
    const vec3 K_s = vec3(.1, .1, .1);
    
    const float shininess = 3.5;
    
    const vec3 lightIntensity = vec3(0.7, 0.7, 0.7);
    
    vec3 phongContribForLight(vec3 k_d, vec3 k_s, float alpha, vec3 p, vec3 eye,
                              vec3 lightPos, vec3 lightIntensity) {
    
        vec3 N = estimateNormal(p);
        vec3 L = normalize(lightPos - p);
        vec3 V = normalize(eye - p);
        vec3 R = normalize(reflect(-L, N));
    
        float dotLN = dot(L, N);
        float dotRV = dot(R, V);
    
    
        if (dotLN < 0.0) {
            // Light not visible from this point on the surface
            return vec3(0.0, 0.0, 0.0);
        }
    
        if (dotRV < 0.0) {
            // Light reflection in opposite direction as viewer, apply only diffuse
            // component
            return lightIntensity * (k_d * dotLN);
        }
    
        return lightIntensity * (k_d * dotLN + k_s * pow(dotRV, alpha));
    }
    
    
    vec3 phongIllumination(vec3 k_a, vec3 k_d, vec3 k_s, float alpha, vec3 p, vec3 eye, vec3 materialColor) {
    
        vec3 color = materialColor * k_a;
        color += phongContribForLight(k_d, k_s, alpha, p, eye, lightPos, lightIntensity);
    
        return color;
    }
    
    
    vec3 decodeMaterialColor(float material) {
    
        float r = material * 10.;
        r = r - fract(r);
        r = r/10.;
    
        float g = material * 100. - r * 100.;
        g = g - fract(g);
        g = g/10.;
    
        float b = material * 1000. - r * 1000. - g * 100.;
        b = b - fract(b);
        b = b/10.;
    
        return vec3(r, g, b);
    }
    
    vec3 phong(vec3 p, vec3 eye, float material) {
        vec3 materialColor = decodeMaterialColor(material);
        return phongIllumination(K_a, K_d, K_s, shininess, p, eye, materialColor);
    }
    
    // http://iquilezles.org/www/articles/rmshadows/rmshadows.htm
    float softShadow( in vec3 ro, in vec3 rd, in float mint, in float tmax ){
    	float res = 1.0;
        float t = mint;
        for( int i=0; i<12; i++ )
        {
    		float h = map( ro + rd*t ).x;
            res = min( res, 8.0*h/t );
            t += clamp( h, 0.02, 0.10 );
            if( res<0.005 || t>tmax ) break;
        }
        return clamp( res, 0.0, 1.0 );
    }
    
    // ambient occlusion
    float ao( in vec3 pos, in vec3 nor ){
    	float occ = 0.0;
        float sca = 1.0;
        for( int i=0; i<5; i++ )
        {
            float hr = 0.01 + 0.12*float(i)/4.0;
            vec3 aopos =  nor * hr + pos;
            float dd = map( aopos ).x;
            occ += -(dd-hr)*sca;
            sca *= 0.95;
        }
        return clamp( 1.0 - 3.0*occ, 0.0, 1.0 );
    }
    
    void main(void) {
    	vec3 direction = rayDirection(60.0, resolution);
        mat4 viewToWorld = viewMatrix(eye, vec3(0.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0));
        vec3 worldDir = (viewToWorld * vec4(direction, 0.0)).xyz;
        vec2 dist = castRay(eye, worldDir);
        if (dist.x > 24.) {
            gl_FragColor = vec4(0.9, 0.9, 0.9, 1.0);
        } else {
            vec3 pt = eye + dist.x * worldDir;
            vec3 nor = estimateNormal( pt );
            float occ = ao( pt, nor );
            float shadow = softShadow( pt, normalize(lightPos-pt), 0.1, 22.2);
            vec3 color = phong(pt, eye, dist.y)*sqrt(occ);
            color += color * shadow;
            gl_FragColor = vec4(color, 1.0);
        }
    }
        `;
    </script>
    
    <script>
    function GLx() {
    
        var canvas = document.createElement('canvas');
        document.body.appendChild(canvas);
        var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
    
        return {
            gl: gl,
            buffer: buffer,
            program: program,
            resize: resize
        };
    
        function program(vs, fs) {
            var pid = gl.createProgram(); // program id
            shader(vs, gl.VERTEX_SHADER);
            shader(fs, gl.FRAGMENT_SHADER);
            gl.linkProgram(pid);
    
            var p = {
                uniform: uniform,
                attribute: attribute,
                use: use
            };
    
            return p;
    
            function use() {
                gl.useProgram(pid);
                return p;
            }
    
            function attribute(name, count) {
                var al = gl.getAttribLocation(pid, name);
    
                return {
                    bind: bind
                };
    
                function bind(buffer) {
                    buffer.bind();
                    gl.vertexAttribPointer(al, count, gl.FLOAT, false, 0, 0);
                    gl.enableVertexAttribArray(al);
                }
            }
    
            function uniform(type, name) {
                var ul = gl.getUniformLocation(pid, name);
    
                return {
                    set: set
                };
    
                function set(v1, v2, v3, v4) {
                    gl['uniform' + type](ul, v1, v2, v3, v4);
                }
            }
    
            function shader(src, type) {
                var sid = gl.createShader(type);
                gl.shaderSource(sid, src);
                gl.compileShader(sid);
                var message = gl.getShaderInfoLog(sid);
                if (message.length > 0){
                    console.log(src.split('\n').map(function (str, i) {
                        return ("" + (1 + i)).padStart(4, "0") + ": " + str
                    }).join('\n'));
                    throw message;
                }
                gl.attachShader(pid, sid);
            }
        }
    
        function buffer(data) {
            var array = new Float32Array(data);
            var buffer = gl.createBuffer();
            var type = gl.ARRAY_BUFFER;
            gl.bindBuffer(type, buffer);
            gl.bufferData(type, array, gl.STATIC_DRAW);
            gl.bindBuffer(type, data = null);
    
            return {
                bind: bind
            };
    
            function bind() {
                gl.bindBuffer(type, buffer);
            }
        }
    
        function resize() {
            var c = canvas;
            if (c.clientWidth !== c.width || c.clientHeight !== c.height) {
                c.width = c.clientWidth;
                c.height = c.clientHeight;
                return true;
            }
        }
    }
    
    // full-screen-triangle with webgl
    
    function FullScreenTriangle(fragCode) {
    
        var glx = GLx();
    
        var vertices = glx.buffer([-1,  3, -1, -1, 3, -1]);
    
        var vertCode =
            `attribute vec2 coords;
         void main(void) {
           gl_Position = vec4(coords.xy, 0.0, 1.0);
         }`;
    
        glx.triangleProgram = glx.program(vertCode, 'precision highp float;' + fragCode).use();
        glx.triangleProgram.attribute("coords", 2).bind(vertices);
    
        glx.draw = function () {
            var gl = glx.gl;
            glx.resize();
            gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
            gl.clearColor(0, 0, 0, 1);
            gl.drawArrays(gl.TRIANGLES, 0, 3);
        };
    
        return glx;
    }
    
    
    var Mouse3D = (function(){
    
        var theta = 0;
        var phi = 0;
        var mouse = {x: 0, y: 0};
        var radius = 7;
        var dragStartMousePosition, dragStartPhi, dragStartTheta;
        var callback;
        var mouse3d = {
            init: init,
            eye: [0, 0, radius],
            callback: function (cb) {
                callback = cb;
            }
        };
    
        return mouse3d;
    
        function init() {
            window.addEventListener('mousemove', mouseMove, false);
            window.addEventListener('mouseup', mouseUp, false);
            window.addEventListener('mousedown', mouseDown, false);
            window.addEventListener('mousewheel', mouseWheel, false);
        }
    
        function mouseMove(event) {
            if (event.target.tagName !== 'CANVAS') return;
            mouse = event;
            if (dragStartMousePosition) {
                rotate();
            }
        }
    
        function updateCameraPosition() {
            mouse3d.eye[0] = radius * Math.cos(phi) * Math.sin(theta);
            mouse3d.eye[1] = radius * Math.sin(phi);
            mouse3d.eye[2] = radius * Math.cos(phi) * Math.cos(theta);
            callback && callback();
        }
    
        function rotate() {
            var amountX = dragStartMousePosition ? dragStartMousePosition.x - mouse.x : 0;
            var amountZ = mouse.y - dragStartMousePosition.y;
            theta = dragStartTheta + amountX/120;
            phi = dragStartPhi + amountZ/120;
            var limit = Math.PI / 2;
            phi = phi > limit ? limit : phi;
            phi = phi < -limit ? -limit : phi;
            updateCameraPosition();
        }
    
        function mouseDown(event) {
            if (event.target.tagName !== 'CANVAS') return;
            dragStartPhi = phi;
            dragStartTheta = theta;
            dragStartMousePosition = event;
        }
    
        function mouseUp() {
            if (event.target.tagName !== 'CANVAS') return;
            rotate();
            dragStartMousePosition = null;
            dragStartPhi = 0;
            dragStartTheta = 0;
        }
    
        function mouseWheel(e){
            radius *= e.wheelDelta > 0 ? 0.9 : 1.1;
            updateCameraPosition();
        }
    })();
    
    Mouse3D.init();
    
    let fst = FullScreenTriangle(fragCode);
    let resolution = fst.triangleProgram.uniform('2f', 'resolution');
    let lightPos = fst.triangleProgram.uniform('3f', 'lightPos');
    let time = fst.triangleProgram.uniform('1f', 'time');
    let eye = fst.triangleProgram.uniform('3f', 'eye');
    addEventListener('mousemove', drawFrame);
    animate();
    var started = new Date().getTime();
    
    function animate() {
        requestAnimationFrame(animate);
        drawFrame();
    }
    
    function drawFrame() {
        let t = (new Date().getTime() - started)/1000;
        resolution.set(fst.gl.drawingBufferWidth, fst.gl.drawingBufferHeight);
        time.set(t);
        lightPos.set(Math.cos(t/10)*10,10,Math.sin(t/10)*10);
        eye.set(Mouse3D.eye[0], Mouse3D.eye[1], Mouse3D.eye[2]);
        fst.draw();
    }
    
    </script>
    <style>
    body, canvas {
        position: absolute;
        width: 100%;
        height: 100%;
        overflow: hidden;
        margin: 0;
    }
    </style>

    Это все придумано давным давно, однако раньше, трассировка лучей в реальном времени была фантастикой и таким образом создавали статические картинки. сегодня каждый обладатель компьютера с видеокартой может написать фрагментный шейдер, который делает трассировку простеньких (и не очень) сцен в реальном времени.

    Для этого потребуются:

    • Желание разбираться с математикой
    • Много свободного времени
    • Видеокарта, у меня gtx1050ti (768 вычислительных ядер) и это мало :(
    • Браузер с поддержкой WebGL

    Во фрагменте кода приведена уже склеенная версия, исходник на github gists и blocks.

    Итак, попробую по-простому описать что тут происходит, т.к. код вы можете и сами почитать.

    Для начала WebGL инициализируется таким образом, чтобы нарисовать один треугольник, который покрывает весь экран как на изображении ниже, или как-то иначе, главное вызвать фрагментный шейдер для каждого пикселя.

    在此处输入图像描述

    Фрагментный шейдер делает всю работу.

    Перед формированием каждого кадра, из javascript в шейдер передаются некоторые переменные, которые характеризуют сцену, тут это положение наблюдателя в декартовых координатах, размер картинки, и еще для анимации понадобится время.

    Конечно перед каждым кадром обновлять все uniform переменные не нужно, но в этом примере я сделал так для простоты кода.

    —-

    Далее в каждом фрагменте(пикселе) происходит трассировка луча:

    在此处输入图像描述

    В нашем случае это raymarching, что про сути есть оптимизация шага трассировки.

    在此处输入图像描述

    В отличие от классического представления объектов сцены в виде треугольников, тут используются математические формулы дистанции до поверхностей(так называемые signed distance fields, SDF). Шагая вдоль луча, применяется огромная формула (функция map(vec3)), которая вычисляет дистанцию от точки-аргумента до всех объектов в сцене и возвращает минимальную. Дистанция которую вернула эта функция - безопасное расстояние, шагнув на которое, мы точно не во что не упремся.

    Собственно это будет длина следующего шага, вдоль луча, и так до тех пор, пока луч не упрется в поверхность.

    vec2 map(vec3 p) {
        vec2 res = vec2(VERY_FAR, -1);
    
        res = opU( res, snow(p) );
        res = opU( res, snowmans_accesories(p) );
        res = opU( res, tree(p) );
    
        return res;
    }
    

    Изначально результат инициализируется расстоянием очень далеким от наблюдателя, т.е. будущим фоном. -1 выступает в роли идентификатора материала.

    Функция opU - названа от слов operation и union и предназначена для объединения объектов сцены.

    Каждый компонент, объединяемый этой операцией это в свою очередь тоже функция, только описывающая один объект сцены плюс возвращающая вторым компонентом идентификатор(цвет) материала. Объекты, в свою очередь, состят из более простых примитивов: сфер, цилиндров, кубов, фракталов, поверхностей безье, чего душе угодно, между которыми возможно всевозможные трансформации, булевые операции итд.

    Все вместе это и описывает сцену .

    После того, как точка где луч уперся в поверхность найдена - начинается самое сложное и самое интересное, это определение цвета найденной точки.

    В этой сцене цвет состоит из нескольких компонентов:

    • Цвет поверхности (diffuse)
    • Модель освещения по Фонгу(phong shading)
    • Самозатенение ambient occlusion
    • Мягкие тени (soft shadows)

    Этот список можно было бы продолжать всякими экранными эффектами, компонентами других моделей освещения и чего еще только не напридумывали.

    Непосредственно при моделировании никаких сложных примитивов не использовано, все объекты собраны из

    сфер

    float sdSphere( vec3 p, float s ){
        return length(p)-s;
    }
    

    плоскостей

    // horizontal
    float sdPlane( vec3 p , float down){
        return p.y - down;
    }
    
    float plane(vec3 p, vec3 n, float offs) {
        return dot(p, n) - offs;
    }
    

    усеченных конусов

    float sdCappedCone( in vec3 p, in float h, in float r1, in float r2 ){
        vec2 q = vec2( length(p.xz), p.y );
        vec2 k1 = vec2(r2,h);
        vec2 k2 = vec2(r2-r1,2.0*h);
        vec2 ca = vec2(q.x-min(q.x,(q.y < 0.0)?r1:r2), abs(q.y)-h);
        vec2 cb = q - k1 + k2*clamp( dot(k1-q,k2)/dot2(k2), 0.0, 1.0 );
        float s = (cb.x < 0.0 && ca.y < 0.0) ? -1.0 : 1.0;
        return s*sqrt( min(dot2(ca),dot2(cb)) );
    }
    

    цилиндра

    float sdCylinder( vec3 p, vec2 h ){
        vec2 d = abs(vec2(length(p.xz),p.y)) - h;
        return min(max(d.x,d.y),0.0) + length(max(d,0.0));
    }
    

    и шума(noise), для создания "сугробов":

    float hash(vec3 p) {
        p  = fract( p*0.3183099+.1 );
        p *= 17.0;
        return fract( p.x*p.y*p.z*(p.x+p.y+p.z) );
    }
    float noise( in vec3 x ){
        vec3 p = floor(x);
        vec3 f = fract(x);
        f = f*f*(3.0-2.0*f);
        return mix(mix(mix( hash(p+vec3(0,0,0)),
                            hash(p+vec3(1,0,0)),f.x),
                       mix( hash(p+vec3(0,1,0)),
                            hash(p+vec3(1,1,0)),f.x),f.y),
                   mix(mix( hash(p+vec3(0,0,1)),
                            hash(p+vec3(1,0,1)),f.x),
                       mix( hash(p+vec3(0,1,1)),
                            hash(p+vec3(1,1,1)),f.x),f.y),f.z);
    }
    

    Так же тут используется отражение и поворот пространства, для создания 6 снеговиков и звезды, операция smoothMin для создания плавных переходов между поверхностями

    Upd2: добавил деталей, теперь летит снег и взаимодействует с другим снегом в сцене при помощи smooth minimum, двигается источник света, самую актуальную версию смотрите тут

    PPS: все происходящее тут можно сильно оптимизировать, начиная от шума, который тут считается каждый раз, его можно либо запечь в текстуру, либо сразу предоставить текстуру шума, затем функция map()... для разных частей освещения или эффектов можно использовать различные упрощенные версии map() кандидаты на это - построение теней, ambient occlusion, из последнего убрать бы летящий снег, сам raymarching тоже может быть оптимизирован на счет первоначальной трассировки более простых сцен(кубов или сфер в которых вписаны объекты сцены), для уменьшения количества шагов трассировки

    PPPS: Где можно про это почитать:

    1. Сайт Inigo Quilez.
    2. Простенький туториал от Jamie Wong
    3. Ну и конечно же гуглёж по терминам

      • signed distance field(function), SDF

      • raymarching, raytracing


    UPD 31.03.2019: Починил ( правда ценой производительности (: ) артефакты прошлой версии, когда при взгляде сверху появлялись черно-цветные полосы.

    在此处输入图像描述

    • 47
  3. Best Answer
    HamSter
    2020-12-28T23:00:39Z2020-12-28T23:00:39Z

    ВНИМАНИЕ! Ёлка не идеальна и только для современных браузеров и только в качестве примера!

    🎄 ПРИМЕР НА CODEPEN.

    *Скомпилированный код не вмещается в ответ на so.


    Технологии: pug, sass/scss, svg


    ЗАДАЧА 1. ЁЛОЧКА

    Хотелось сделать ёлочку с большими звездочками по середине и равномерным уменьшением к краям т.е. задать необходимые для этого условия в pug и scss файлах.

    Код от участника @Grundy:

    pug:

    mixin row(n)
      if n == 1
        i(class = 'c-'+n)
      else
        i(class = 'c-'+n)
        +row(n-2)
        i(class = 'c-'+n)
    
    .box
      .tree
        - var n = -1;
        while n++ < 6
          .x
            +row(2*n +1)
    

    scss:

    @for $j from 1 through $n {
      .c-#{$j} {
        width:  (21 - $j) + 0px;
        height: (21 - $j) + 0px;
      }
    }
    

    Codepen

    Скомпилированный код:

    html,
    body {
      padding: 0;
      margin: 0;
      width: 100%;
      height: 100%;
    }
    .box {
      width: 100%;
      height: 100%;
      text-align: center;
      display: flex;
      align-items: center;
      justify-content: center;
      background: #4a5c12;
    }
    .x {
      display: flex;
      flex-flow: row wrap;
      align-items: center;
      justify-content: center;
    }
    .tree {
      width: 100%;
      height: 100%;
    }
    i {
      display: block;
      font-style: normal;
    }
    svg {
      width: 100%;
      height: 100%;
    }
    path {
      fill: #fff;
    }
    .tree {
      max-width: 230px;
      max-height: 230px;
    }
    .tree i {
      background: #fff;
      border-radius: 50%;
    }
    .c-1 {
      width: 20px;
      height: 20px;
      line-height: 20px;
      margin: 0 2px;
    }
    .c-2 {
      width: 19px;
      height: 19px;
      line-height: 19px;
      margin: 0 2px;
    }
    .c-3 {
      width: 18px;
      height: 18px;
      line-height: 18px;
      margin: 0 2px;
    }
    .c-4 {
      width: 17px;
      height: 17px;
      line-height: 17px;
      margin: 0 2px;
    }
    .c-5 {
      width: 16px;
      height: 16px;
      line-height: 16px;
      margin: 0 2px;
    }
    .c-6 {
      width: 15px;
      height: 15px;
      line-height: 15px;
      margin: 0 2px;
    }
    .c-7 {
      width: 14px;
      height: 14px;
      line-height: 14px;
      margin: 0 2px;
    }
    .c-8 {
      width: 13px;
      height: 13px;
      line-height: 13px;
      margin: 0 2px;
    }
    .c-9 {
      width: 12px;
      height: 12px;
      line-height: 12px;
      margin: 0 2px;
    }
    .c-10 {
      width: 11px;
      height: 11px;
      line-height: 11px;
      margin: 0 2px;
    }
    .c-11 {
      width: 10px;
      height: 10px;
      line-height: 10px;
      margin: 0 2px;
    }
    .c-12 {
      width: 9px;
      height: 9px;
      line-height: 9px;
      margin: 0 2px;
    }
    .c-13 {
      width: 8px;
      height: 8px;
      line-height: 8px;
      margin: 0 2px;
    }
    .c-14 {
      width: 7px;
      height: 7px;
      line-height: 7px;
      margin: 0 2px;
    }
    .c-15 {
      width: 6px;
      height: 6px;
      line-height: 6px;
      margin: 0 2px;
    }
    .c-16 {
      width: 5px;
      height: 5px;
      line-height: 5px;
      margin: 0 2px;
    }
    .c-17 {
      width: 4px;
      height: 4px;
      line-height: 4px;
      margin: 0 2px;
    }
    .c-18 {
      width: 3px;
      height: 3px;
      line-height: 3px;
      margin: 0 2px;
    }
    .c-19 {
      width: 2px;
      height: 2px;
      line-height: 2px;
      margin: 0 2px;
    }
    .c-20 {
      width: 1px;
      height: 1px;
      line-height: 1px;
      margin: 0 2px;
    }
    <div class="box">
      <div class="tree">
        <div class="x"><i class="c-1"></i>
        </div>
        <div class="x"><i class="c-3"></i><i class="c-1"></i><i class="c-3"></i>
        </div>
        <div class="x"><i class="c-5"></i><i class="c-3"></i><i class="c-1"></i><i class="c-3"></i><i class="c-5"></i>
        </div>
        <div class="x"><i class="c-7"></i><i class="c-5"></i><i class="c-3"></i><i class="c-1"></i><i class="c-3"></i><i class="c-5"></i><i class="c-7"></i>
        </div>
        <div class="x"><i class="c-9"></i><i class="c-7"></i><i class="c-5"></i><i class="c-3"></i><i class="c-1"></i><i class="c-3"></i><i class="c-5"></i><i class="c-7"></i><i class="c-9"></i>
        </div>
        <div class="x"><i class="c-11"></i><i class="c-9"></i><i class="c-7"></i><i class="c-5"></i><i class="c-3"></i><i class="c-1"></i><i class="c-3"></i><i class="c-5"></i><i class="c-7"></i><i class="c-9"></i><i class="c-11"></i>
        </div>
        <div class="x"><i class="c-13"></i><i class="c-11"></i><i class="c-9"></i><i class="c-7"></i><i class="c-5"></i><i class="c-3"></i><i class="c-1"></i><i class="c-3"></i><i class="c-5"></i><i class="c-7"></i><i class="c-9"></i><i class="c-11"></i><i class="c-13"></i>
        </div>
      </div>
    </div>


    Пришлось обратится за помощью, но потом и меня осенила собственная идея:

    pug:

    -var x = 7
      .tree
        - for (var i = 0; i < x; i++)
          .x
            .inc
              - for (var a = 0; a < i; a++)
                svg
            .mid
              svg
            .dec
              - for (var b = i; b < 2*i; b++)
                svg
    

    scss:

    .inc {
      flex-flow: row-reverse nowrap;
    }    
    
    @for $i from 1 through $n/2  {    
      .tree svg:nth-of-type(#{$i}) {
        width:  $w/$n/$i + 0px;
        height: $w/$n/$i + 0px;   
      }  
    }
    

    Получилось не так изящно. Смысл в том, что создаю строки .x, в каждой строке 3 блока .inc (по возрастанию), .dec (по убыванию для его реализации в стилях задаю flex-row: row-reverse) и .mid (серединка).


    ЗАДАЧА 2. СНЕГ

    Признаюсь честно, за основу был взят плагин magic-snowflakes, но код js преобразован в scss:

    pug:

    .snowflakes
        -var snow = 15
          - for (var i = 0; i < snow; i++)
            span
              i
    

    scss:

    @for $i from 1 through $snow-n {    
      .snowflakes span:nth-of-type(#{$i}) {
        animation-delay: random(1) + 0s;
        animation-duration: randomNum(10, 30) + 0s;
        left: random(100) + 0%;
        margin-top: -1*random(1)*$snow-w + 0px;
        width: $snow-w + 0px;
        height: $snow-w + 0px;
        z-index: 10099;
        opacity: random(1);
    
        i {
          animation-name: snowflake_x_#{$i};
          animation-delay: random(1) + 0s;
        }
      }  
    }
    

    codepen


    ЗАДАЧА 3. НАДПИСЬ (Handwriting)

    За пример были взяты работы с codepen: пример1,пример2. Перепробовав все возможные варианты:

    • Открываем adobe illustrator
    • Пишем любой текст, задаем необходимый шрифт, размер
    • Выбираем слой текст и жмем: CTRL+SHIFT+O или Type -> Create outlines
    • Это все будет наш clip-path. Блокируем этот слой.
    • Создаем новый слой или группу слоев.
    • Выбираем карандаш и аккуратно (на сколько это возможно) прорисовываем каждую букву по отдельности.
    • Это будет наш stroke который мы будем анимировать.
    • Сохраняем в svg вставляем в html(pug) код.

    Анимация заключается в изменении значения stroke-dashoffset:

    path {
      stroke-width: 7; 
      animation: dash 8s linear forwards infinite; 
      stroke-dasharray: 2200;
      stroke-dashoffset: 2200;
    }
    @keyframes dash {
      0% {
        stroke-dashoffset: 2200;
      }
      100% {
        stroke-dashoffset: 0;
      }
    }
    

    При этом важно задать stroke-width такой, чтобы полностью заполнить букву.

    Получаем: codepen

    P.S: буквы обрисовала не аккуратно, поэтому есть заметные изъяны).


    Итого:

    🎄 ПРИМЕР НА CODEPEN.

    ❄ ❄ ❄ ❄ ❄ ❄ ❄

    С наступающим Новым Годом! Мира всем и добра!

    ❄ ❄ ❄ ❄ ❄ ❄ ❄

    • 40
  4. Misha Saidov
    2020-12-23T05:23:07Z2020-12-23T05:23:07Z

    А вот и Ёлочка!

    Я плох в векторной графике и канвасе, но что-то смыслю в математике, поэтому как смог :) В общем, можно заметить, что есть очень много общего со скриптом снежинок, который я кидал ранее. Соль заключается в том, что позиционированием звездочек полностью занимается js при помощи функции y=sin(x)*x, график которой похож на елку. Перевернув эту функцию на 90 градусов можно получить точки расположения звездочек по оси Y. Размер звездочек вариативный, но зависит от смещения сверху: чем ниже, тем больше звезда, как на картинке. Немного визуальных эффектов и вот :) Хорошо себя чувствует при ресайзе, разверните на весь экран, для примера. Не совсем похоже, конечно, но, думаю, имеет место быть.

    let params = {
      amount: 800,
      duration: {
        min: 8,
        max: 20
      },
      size: {
        min: 20,
        max: 45
      }
    }
    
    const randomBetween = (a, b) => {
      return (a + (Math.random() * (b - a)));
    }
    const randomArr = (arr) => {
      return arr[Math.round(Math.random() * (arr.length - 1))];
    }
    
    $(document).ready(() => {
      for (let i = 0; i < params.amount; i++) {
        let star = $("<img class='star' src='https://vignette.wikia.nocookie.net/justdance/images/2/2e/Star.png/revision/latest?cb=20160307193808'>");
        let top = randomBetween(0, randomBetween(50, 100));
        let randomSize = (randomBetween(params.size.min, params.size.max) * top / 100);
        star.css({
          "width": randomSize + "px",
          "height": randomSize + "px",
          "left": "calc(50% - " + (Math.sin(top) * top) + "px)",
          "top": top * 3 + "px",
          "animation-duration": randomBetween(params.duration.min, params.duration.max) + "s",
          "transform-origin": (50 + randomBetween(-15, +15)) + "% " + (50 + randomBetween(-15, 15)) + "%"
        });
    
        $("#root").append(star);
      }
    });
    body,
    html {
      margin: 0;
      width: 100%;
      height: 300px;
      background: green;
    }
    
    #root {
      position: absolute;
      width: 100%;
      height: 100%;
      filter: drop-shadow(0 0 2px white);
      overflow: hidden;
    }
    
    .main-star {
      position: absolute;
      top: 3px;
      left: calc(50% - 15px);
      z-index: 9;
      width: 30px;
      height: 30px;
    }
    
    .star {
      position: absolute;
      animation-name: shake;
      transform-origin: center center;
      animation-iteration-count: infinite;
      animation-timing-function: ease-in-out;
    }
    
    @keyframes shake {
      0%,
      100% {
        transform: rotate(0deg) scale(1);
        opacity: 0;
      }
      10% {
        transform: rotate(50deg) scale(.5);
        opacity: 0.7;
      }
      20% {
        transform: rotate(184deg) scale(.7);
        opacity: 0.8;
      }
      30% {
        transform: rotate(365deg) scale(1);
        opacity: 0.7;
      }
      40% {
        transform: rotate(130deg) scale(.6);
        opacity: 0.9;
      }
      50% {
        transform: rotate(10deg) scale(0);
        opacity: 1;
      }
      60% {
        transform: rotate(46deg) scale(.4);
        opacity: 0.8;
      }
      70% {
        transform: rotate(360deg) scale(.1);
        opacity: 0.6;
      }
      80% {
        transform: rotate(240deg) scale(.5);
        opacity: 0.5;
      }
      90% {
        transform: rotate(200deg) scale(.9);
        opacity: 0.2;
      }
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    
    <div id="root">
      <img class="main-star" src="https://vignette.wikia.nocookie.net/justdance/images/2/2e/Star.png/revision/latest?cb=20160307193808">
    </div>

    • 35
  5. Alexandr_TT
    2020-12-23T01:29:59Z2020-12-23T01:29:59Z

    我要开始播种了。
    比赛将于今天开始 - 2018年 12 月 24 日,奖励丰厚。
    我们将在新年前夕总结结果。

    例如,我将从问题列表中制作动画的第一项。由于我将在此空白中使用基本的 svg 命令和简单、众所周知的技巧,因此您可以安全地在比赛答案中使用它们,这不会被视为复制粘贴。

    来自星星的光线。

    我是用 SVG 做的,当然可以在CSS, Javascript,上实现jQuery

    <svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="400" height="400" viewBox="0 0 400 400">   
    	
    	<defs>
    	   <radialGradient id="radGrad" cx="50%" cy="50%" r="25%"
          fx="50%" fy="80%">
          <stop offset="10%" style="stop-color:yellow;
          stop-opacity:1">
    	  <animate
    	  attributeName="offset"
    	  values="10%;90%;10%"
    	  dur="1.5s"
    	  repeatCount="indefinite"/>
    	  </stop>
          <stop offset="90%" style="stop-color:gold;
          stop-opacity:1.0"/>
    	   </radialGradient>  
    	   
    	    <radialGradient id="starGrad" cx="50%" cy="50%" r="65%"
          fx="50%" fy="50%">
          <stop offset="10%" style="stop-color:yellow;
          stop-opacity:1;">
    	  <animate
    	  attributeName="offset"
    	  values="10%;90%;10%"
    	  dur="2.5s"
    	  repeatCount="indefinite"/>
    	  </stop>
          <stop offset="90%" style="stop-color:crimson;
          stop-opacity:1;"/>
    	   </radialGradient>
    	  
    	</defs> 
    	<rect width="100%" height="100%" fill="#DBFF66"/>
    	<path transform="translate(100 105)" d="M100,10 L100,10 40,180 190,60 10,60 160,180 z" stroke="gold" stroke-width="4" fill-opacity="0.75" fill="url(#starGrad)" />
    	
    	<circle cx="200" cy="200" r="150" fill="yellow" fill-opacity="0.25" stroke="url(#radGrad)" stroke-dasharray="13.08 13.08" stroke-width="250" >
    	 <animate 
    	 attributeName="stroke-width"
    	 fill="yellow"
    	 fill-opacity="0.15"
    	 values="0;300;0"
    	 dur="8s"
    	 repeatCount="indefinite" /> 
    	<!--  <animateTransform
    	  attributeName="transform"
    	  type="rotate"
    	  values="0 200 200;180 200 200"
    	  dur="8s"
    	  repeatCount="indefinite"/> -->
    	 </circle> 
    	
    
    </svg>

    如何使用 SVG 来做到这一点

    • 有一个半径r="100",周长是 2 * 3,14 * 100 = 628px
    • 你需要得到 12 条光线 + 12 个间隙 = 24 个相等的部分。一部分等于26,16px 将条的长度和间距代入属性

      <circle stroke-dasharray="26.16 26.16"
      

    <svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="400" height="400" viewBox="0 0 400 400" >   
     <circle cx="200" cy="200" r="100"
        fill="none"
        stroke="yellowgreen"
        stroke-dasharray="26.16 26.16"
        stroke-width="4" />
    </svg>

    • 将线宽增加到stroke-width="200"

    由于线对称地放置在圆中心线的两侧,
    其r="100px"宽度必须200px填满圆的内部空间。

    为了演示,圆圈用颜色填充。fill="purple"

    <svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="400" height="400" viewBox="0 0 400 400" >   
     <circle cx="200" cy="200" r="100"
        fill="purple"
        stroke="yellowgreen"
        stroke-dasharray="26.16 26.16"
        stroke-width="200" />
    </svg>

    雪花原型

    我们删除填充fill="none"并分配stroke="#87CEFA"

    <svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="400" height="400" viewBox="0 0 400 400">   
     <circle cx="200" cy="200" r="100"
        fill="none"
        stroke="#87CEFA"
        stroke-dasharray="26.16 26.16"
        stroke-width="200" />
    </svg>

    • 在光线的中心添加一个星号

    <svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="400" height="400" viewBox="0 0 400 400"  >  
    <path transform="translate(100 105)" d="M100,10 L100,10 40,180 190,60 10,60 160,180 z" stroke="gold" stroke-width="4" fill-opacity="0.75" fill="yellow" />
    		
     <circle cx="200" cy="200" r="100"
        fill="none"
        stroke="yellowgreen"
        stroke-dasharray="26.16 26.16"
        stroke-width="200" />
    </svg>

    • 添加星光的渐变和动画,可惜这个版本的动画只适用于FF这段代码被注释掉了

      <defs>
          <radialGradient id="radGrad" cx="50%" cy="50%" r="150%"
            fx="50%" fy="50%">
              <stop offset="10%" style="stop-color:#D3B300; stop-opacity:1">
                  <!--  <animate
                        attributeName="offset"
                        values="1%;90%;1%"
                        dur="2.5s"
                        repeatCount="indefinite"/> -->
              </stop>
              <stop offset="90%" style="stop-color:yellow; stop-opacity:1.0"/>
          </radialGradient>  
      </defs>  
      

    <svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="400" height="400" viewBox="0 0 400 400"  >  
    	
    	<defs>
    	   <radialGradient id="radGrad" cx="50%" cy="50%" r="150%"
          fx="50%" fy="50%">
          <stop offset="10%" style="stop-color:#D3B300;
          stop-opacity:1">
    	<!--  <animate
    	  attributeName="offset"
    	  values="1%;90%;1%"
    	  dur="2.5s"
    	  repeatCount="indefinite"/> -->
    	  </stop>
          <stop offset="90%" style="stop-color:yellow;
          stop-opacity:1.0"/>
    	   </radialGradient>  
    	  </defs> 
     <path transform="translate(100 105)" d="M100,10 L100,10 40,180 190,60 10,60 160,180 z" stroke="gold" stroke-width="4" fill-opacity="0.5" fill="yellow" /> 
    		
        <circle cx="200" cy="200" r="100"
        fill="none"
        stroke="url(#radGrad)"
        stroke-dasharray="26.16 26.16"
        stroke-width="200" /> 
    </svg>

    • 恒星光线旋转的动画

      要将对象顺时针旋转一整圈,您需要在其标签内添加动画命令:

      <animateTransform
            attributeName="transform"
            type="rotate"
            values="0 200 200;360 200 200"
            dur="2s"
            repeatCount="indefinite" />
      

    使用嵌套动画时,对象标签的语义有点棘手。

    为了澄清,这里有一个线程:那些奇怪的 SVG 标签

    下面是星星光线旋转的动画代码

    <svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="400" height="400" viewBox="0 0 400 400" >  
    	
    	<defs>
    	   <radialGradient id="radGrad" cx="50%" cy="50%" r="150%"
          fx="50%" fy="50%">
          <stop offset="10%" style="stop-color:gold;
          stop-opacity:1">
    	<!--  <animate
    	  attributeName="offset"
    	  values="1%;90%;1%"
    	  dur="2.5s"
    	  repeatCount="indefinite"/> -->
    	  </stop>
          <stop offset="90%" style="stop-color:yellow;
          stop-opacity:1.0"/>
    	   </radialGradient>  
    	  </defs> 
     <path transform="translate(100 105)" d="M100,10 L100,10 40,180 190,60 10,60 160,180 z" stroke="gold" stroke-width="4" fill-opacity="0.5" fill="dodgerblue" /> 
    		
        <circle cx="200" cy="200" r="100"
        fill="none"
        stroke="url(#radGrad)"
        stroke-dasharray="26.16 26.16"
        stroke-width="200" >
         <animateTransform
           attributeName="transform"
           type="rotate"
           values="0 200 200;360 200 200"
           dur="2s"
           repeatCount="indefinite" />
    	 </circle>  
    </svg>

    • 使旋转算法复杂化

      values="0 200 200;720 200 200;720 200 200;0 200 200;0 200 200"
      

      顺时针转动 720° → 暂停 → 逆时针转动 720° → 暂停

      <svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
          xmlns:xlink="http://www.w3.org/1999/xlink"  width="400" height="400" viewBox="0 0 400 400" style="border:1px solid red;" >  
      	
      	<defs>
      	   <radialGradient id="radGrad" cx="50%" cy="50%" r="150%"
            fx="50%" fy="50%">
            <stop offset="10%" style="stop-color:gold;
            stop-opacity:1">
      	<!--  <animate
      	  attributeName="offset"
      	  values="1%;90%;1%"
      	  dur="2.5s"
      	  repeatCount="indefinite"/> -->
      	  </stop>
            <stop offset="90%" style="stop-color:yellow;
            stop-opacity:1.0"/>
      	   </radialGradient>  
      	  </defs> 
       <path transform="translate(100 105)" d="M100,10 L100,10 40,180 190,60 10,60 160,180 z" stroke="gold" stroke-width="4" fill-opacity="0.5" fill="dodgerblue" /> 
      		
          <circle cx="200" cy="200" r="100"
          fill="none"
          stroke="url(#radGrad)"
          stroke-dasharray="26.16 26.16"
          stroke-width="200" >
           <animateTransform
             attributeName="transform"
             type="rotate"
             values="0 200 200;720 200 200;720 200 200;0 200 200;0 200 200"
             dur="8s"
             repeatCount="indefinite" />
      	 </circle>  
      </svg>

    • 通过选择角度、它们的顺序以及更改旋转时间 dur="3.43s",您可以获得有趣的效果。

    <svg version="1.1" xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink"  width="400" height="400" viewBox="0 0 400 400"  >  
    	
    	<defs>
    	   <radialGradient id="radGrad" cx="50%" cy="50%" r="150%"
          fx="50%" fy="50%">
          <stop offset="10%" style="stop-color:gold;
          stop-opacity:1">
    	<!--  <animate
    	  attributeName="offset"
    	  values="1%;90%;1%"
    	  dur="2.5s"
    	  repeatCount="indefinite"/> -->
    	  </stop>
          <stop offset="90%" style="stop-color:yellow;
          stop-opacity:1.0"/>
    	   </radialGradient>  
    	  </defs> 
     <path transform="translate(100 105)" d="M100,10 L100,10 40,180 190,60 10,60 160,180 z" stroke="gold" stroke-width="4" fill-opacity="1" fill="dodgerblue" /> 
    		
         <circle cx="200" cy="200" r="100"
        fill="none"
        stroke="url(#radGrad)"
        stroke-dasharray="26.16 26.16"
        stroke-width="200" >
         <animateTransform
           attributeName="transform"
           type="rotate"
           values="0 200 200;1440 200 200;720 200 200;0 200 200"
           dur="3.43s"
           repeatCount="indefinite" />
    </svg>

    • 34
  6. Misha Saidov
    2020-12-23T03:06:26Z2020-12-23T03:06:26Z

    我觉得如果你愿意,可以少用js,但看起来很正常,很漂亮)

    雪花

    let params = {
      amount: 30,
      duration: {
        min: 2,
        max: 6
      }, //s
      size: {
        min: 10,
        max: 20
      }
    }
    
    const randomBetween = (a, b) => {
      return (a + (Math.random() * (b - a)));
    }
    const randomArr = (arr) => {
      return arr[Math.round(Math.random() * (arr.length - 1))];
    }
    
    const snowflakes = [
      "http://pngimg.com/uploads/snowflakes/snowflakes_PNG7578.png",
      "https://vignette.wikia.nocookie.net/fantendo/images/2/27/Snowflake.png/revision/latest?cb=20121220012520",
      "https://latxikadelacerveza.es/wp-content/plugins/christmas-panda/assets/images/snowflake_5.png"
    ];
    
    $(document).ready(() => {
      for (let i = 0; i < params.amount; i++) {
        let snowflake = $("<img class='snowflake' src='" + randomArr(snowflakes) + "'>");
        let randomSize = randomBetween(params.size.min, params.size.max);
        snowflake.css({
          "width": randomSize + "px",
          "height": randomSize + "px",
          "left": randomBetween(0, 100) + "%",
          "animation-duration": randomBetween(params.duration.min, params.duration.max) + "s"
        });
    
        $("#root").append(snowflake);
      }
    });
    body,
    html {
      margin: 0;
      width: 100%;
      height: 100%;
    }
    
    #root {
      position: absolute;
      width: 100%;
      height: 100%;
      background: green;
      overflow: hidden;
    }
    
    .snowflake {
      position: absolute;
      animation-name: drop;
      transform-origin: center center;
      animation-iteration-count: infinite;
      animation-timing-function: linear;
    }
    
    @keyframes drop {
      0% {
        top: 0%;
        opacity: 0;
        transform: rotate(0deg);
      }
      10%,
      90% {
        opacity: 1;
      }
      100% {
        top: 100%;
        opacity: 0;
        transform: rotate(360deg);
      }
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    
    <div id="root">
    </div>

    • 27
  7. Alexandr_TT
    2020-12-26T01:56:47Z2020-12-26T01:56:47Z

    Варианты анимации фразы - С Новым 2019 годом!

    Этот вариант не участвует в конкурсе, создан для примера. Участники могут брать эту технику анимации прорисовки и раскрашивания букв в качестве заготовки и использовать, творчески переработав, в своих конкурсных ответах.

    Как сделать анимацию обводки букв - подробно, с картинками рассказывается как это сделать

    在此处输入图像描述

    update Новый вариант

    <style>
      width:100%;
      heighr:100;
    </style>
    <div class="container">
    <svg xmlns="http://www.w3.org/2000/svg" 
        xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="100%" height="100%" viewBox="0 0 1318 1054" preserveAspectRatio="xMinYMin meet" border="1">
    	  <defs>
    	    <filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
                <feDropShadow dx="5" dy="5" stdDeviation="2"/>
            </filter>
    	  </defs>	
    	<image height="100%" width="100%" xlink:href="https://isstatic.askoverflow.dev/EgAH7.jpg"/>
    	<g fill="transparent" stroke-width="3" transform="translate(0 100)" filter="url(#shadow)">
    	
    	 <path id="L1" transform="translate(-280 -110) scale(1.6)" stroke="gold"  stroke-dasharray="327" stroke-dashoffset="327" d="m248.8 131.1 2.9-6h2.6l1.1 24.8h-2.8q-2.7-10.5-6.9-15.4-5.2-6.2-12.3-6.2-7.7 0-12.6 6.9-4.9 6.9-4.9 23.4 0 13.9 5.6 21.2 4.8 6.2 13.3 6.2 7.5 0 12.6-4.8 5.1-4.8 6.6-14.5h3q-1.3 11-7.5 16.9-6.2 5.9-15.7 5.9-7.7 0-14.2-3.9-6.4-3.9-10.3-11.1-3.8-7.3-3.8-16 0-9.2 4-17.3 4-8.1 10.2-12.1 6.2-4.1 13.4-4.1 4 0 7.8 1.4 3.8 1.4 8.2 4.7zM288.6 126.3">
         <animate id="an_L1" attributeName="stroke-dashoffset" dur="0.8s"  values="327;0" fill="freeze"	/>
    	 <animate id="fill_L1" attributeName="fill" begin="an_L16.end" dur="0.4s"  values="transparent;yellow" fill="freeze"	/>
    	</path> 
    	 
    	 <path id="L2" transform="translate(-290 -110) scale(1.6)" stroke="crimson"  stroke-dasharray="458" stroke-dashoffset="458" d="m288.6 126.3h26.3v3.1h-4.8q-2.5 0-3.3 0.9-0.7 0.9-0.7 4.3v19h28.2v-19q0-3.6-0.7-4.4-0.7-0.8-3.4-0.8h-4.5v-3.1h26.2v3.1h-4.8q-1.8 0-2.5 0.5-0.7 0.5-1.2 1.6-0.2 0.7-0.2 3.7v44.3q0 3.2 0.5 3.9 1.1 1.4 4 1.4h4.3v3.1h-26.2v-3.1h4.5q2.7 0 3.6-1.5 0.5-0.8 0.5-4.2v-21.4h-28.2v21.8q0 3.3 0.5 3.9 1 1.4 3.6 1.4h4.8v3.1h-26.3v-3.1h5q1.3 0 2.1-0.5 0.8-0.5 1.2-1.5 0.2-0.7 0.2-3.5v-44.5q0-3.5-0.8-4.3-0.7-0.9-3.3-0.9h-4.4z"> 
    	  <animate id="an_L2" attributeName="stroke-dashoffset" begin="an_L1.end" dur="0.8s"  values="458;0" fill="freeze"	/>
    	  <animate id="fill_L2" attributeName="fill" begin="fill_L1.end" dur="0.3s"  values="transparent;red" fill="freeze"	/>
    	</path> 
    	 <g id="new" transform="translate(-75)">
    	<path id="L3" stroke="yellowgreen"  stroke-dasharray="346" stroke-dashoffset="346" d="m388.4 125q7.8 0 14.6 4.1 6.8 4.1 10.7 11.5 3.9 7.3 3.9 16.5 0 9.2-3.9 16.6-3.9 7.4-10.7 11.6-6.7 4.1-14.3 4.1-7.4 0-13.9-4-6.5-4.1-10.5-11.6-3.9-7.6-3.9-16.8 0-9.1 3.8-16.4 3.8-7.3 10.5-11.5 6.6-4.2 13.8-4.2zm0.7 3.2q-8.1 0-13.2 6.8-5 6.8-5 22 0 16.5 5.2 22.9 5.2 6.3 12.8 6.3 5.3 0 9.4-2.9 4-2.9 6.4-9.1 2.4-6.2 2.4-16.4 0-11.1-2.2-17.3-2.2-6.2-6.4-9.2-4.2-3-9.3-3z"> 
    	  <animate id="an_L3" attributeName="stroke-dashoffset" begin="an_L2.end" dur="0.5s"  values="346;0" fill="freeze"	/>
    	  <animate id="fill_L3" attributeName="fill" begin="fill_L2.end" dur="0.4s"  values="transparent;greenyellow" fill="freeze"	/>
    	</path> 
    	  <path id="L4" stroke="#00C4FF"  stroke-dasharray="430" stroke-dashoffset="430" d="m426.1 126.3h32.1q9.5 0 14.5 4.2 5 4.2 5 10.5 0 5.3-3.5 8.9-3.5 3.7-10.5 5.8 8.7 1.8 13 5.8 4.4 3.9 4.4 9.9 0 4.6-2.5 8.1-2.5 3.5-8.2 6-5.7 2.5-13.1 2.5h-31.2v-3.1h5.1q2.3 0 3.3-0.7 1.1-0.7 1.1-1.7v-49.4q0-1.7-1-2.6-1-0.9-3-0.9h-5.4zm18.4 28.3h11.7q5.4 0 8.5-3.2 3.2-3.2 3.2-10.4 0-4.5-1.5-7-1.5-2.5-4.4-3.6-2.9-1.2-10-1.2-5 0-6.2 0.8-1.2 0.7-1.2 2.5zm0 3.1v23.8q0 1.7 1 2.5 1 0.8 3.5 0.8h7.5q7.4 0 11-3.2 3.5-3.3 3.5-10.2 0-6.3-3.7-10-3.7-3.7-10.1-3.7z"> 
    	  <animate id="an_L4" attributeName="stroke-dashoffset" begin="an_L3.end" dur="0.5s"  values="430;0" fill="freeze"	/>
    	  <animate id="fill_L4" attributeName="fill" begin="fill_L3.end" dur="0.4s"  values="transparent;cyan" fill="freeze"	/>
    	</path> 
    	     <path id="L5" stroke="#ED00FF"  stroke-dasharray="557" stroke-dashoffset="557" d="m487.8 187.9v-3.1h3.4q2.7 0 3.7-0.5 1-0.6 1.2-1.4 0.3-0.8 0.3-3.3v-46.1q0-2.4-0.7-3.2-0.7-0.8-2.8-0.8h-5v-3.1h28.4v3.1h-7q-2.4 0-3.2 1.1-0.7 1.1-0.7 3.5v19.1h12.5q10.4 0 16.3 4.6 5.9 4.5 5.9 13 0 7.6-5.3 12.4-5.3 4.8-15.9 4.8zm17.4-31.6v23.9q0 2.5 0.9 3.6 0.9 1 3.7 1h5.3q9.5 0 12.4-3.6 2.9-3.6 2.9-10.5 0-7.5-3.6-10.9-3.5-3.5-11.5-3.5zm35.6-30h28.4v3.1h-4.9q-3.2 0-4.1 0.8-0.8 0.8-0.8 3.4v46.7q0 2.8 0.8 3.5 1 1 3.6 1h5.5v3.1h-28.4v-3.1h5.4q2.8 0 3.7-0.8 0.8-0.8 0.8-3.6v-46.7q0-2.7-0.7-3.3-1.2-1-4.3-1h-4.8z"> 
    	  <animate id="an_L5" attributeName="stroke-dashoffset" begin="an_L4.end" dur="0.5s"  values="557;0" fill="freeze"	/>
    	  <animate id="fill_L5" attributeName="fill" begin="fill_L4.end" dur="0.4s"  values="transparent;magenta" fill="freeze"	/>
    	</path>  
    	      <path id="L6" stroke="yellow"  stroke-dasharray="810" stroke-dashoffset="810" d="m573.3 126.3h20.5l18.4 48.7 17-48.7h21v3.1h-5.1q-2.7 0-3.7 0.8-0.9 0.8-0.9 2.8v48.8q0 1.5 1.1 2.3 1.1 0.8 3.9 0.8h4.7v3.1h-28.2v-3.1h5.3q2.3 0 3.3-0.8 1.1-0.9 1.1-2.2v-52.3l-20.4 58.5h-2.8l-21.9-58.3v44.8q0 4 1 6 1 2 2.8 3 1.9 1 6.2 1.3v3.1h-23.2v-3.1q5.7-0.4 7.8-2.5 2-2.1 2-7.4v-42.5q0-1.6-1-2.3-1-0.7-3.6-0.7h-5.2z"> 
    	  <animate id="an_L6" attributeName="stroke-dashoffset" begin="an_L5.end" dur="0.5s"  values="810;0" fill="freeze"	/>
    	  <animate id="fill_L6" attributeName="fill" begin="fill_L5.end" dur="0.4s"  values="transparent;gold" fill="freeze"	/>
    	</path> 
    	     <path id="L7" transform="translate(-420 -110) scale(1.6)" stroke="crimson"  stroke-dasharray="810" stroke-dashoffset="810" d="m689.5 178.8q-1.9 2.5 18.9 2.5 3.1 0 4.5-1.6 1.3-1.6 3-9h2.8l-1.3 17.3h-37.3v-2.2l12.1-13.8q10.1-11 12.2-13.8 2.9-4 4.3-7.8 1.3-3.8 1.3-6.9 0-5.1-2.8-8-2.8-3-7.9-3-5.7 0-9.2 2.7-3.6 2.7-3.6 5.8 0 1 0.5 1.6 0.5 0.5 2.2 1 4.2 1 4.2 4.9 0 2.1-1.4 3.5-1.4 1.4-3.6 1.4-2.5 0-4.5-2.3-1.9-2.4-1.9-6.2 0-4.2 2.2-7.7 2.2-3.5 6.6-5.7 4.4-2.3 9.5-2.3 5 0 9.3 2.2 4.3 2.2 6.5 5.7 2.2 3.5 2.2 7.7 0 2.9-1.1 5.8-1.1 3-3.2 5.5-3.6 4.5-7.4 7.6l-11 9.3q-4.2 3.5-6.1 6z"> 
    	  <animate id="an_L7" attributeName="stroke-dashoffset" begin="an_L6.end" dur="0.5s"  values="810;0" fill="freeze"	/>
    	  <animate id="fill_L7" attributeName="fill" begin="fill_L6.end" dur="0.4s"  values="transparent;red" fill="freeze"	/>
    	</path>  
    	    	
    	    <path id="L8" transform="translate(-420 -110) scale(1.6)" stroke="crimson"  stroke-dasharray="292" stroke-dashoffset="292" d="m747.4 129.1q8.1 0 13.5 6.3 6.7 7.8 6.7 23.6 0 14.7-5.8 22.4-5.8 7.7-14.1 7.7-8 0-13.3-6.5-6.7-8.1-6.7-23.5 0-14.6 6.3-23.2 5-6.9 13.3-6.9zm0.3 3q-5.5 0-8.6 5.3-3.1 5.3-3.1 21.8 0 16.2 3.2 21.6 3.2 5.4 8.6 5.4 5.4 0 8.3-5 3.5-6 3.5-21.7 0-16.3-3.2-21.9-3.2-5.5-8.6-5.5z"> 
    	  <animate id="an_L8" attributeName="stroke-dashoffset" begin="an_L7.end" dur="0.5s"  values="292;0" fill="freeze"	/>
    	  <animate id="fill_L8" attributeName="fill" begin="fill_L7.end" dur="0.4s"  values="transparent;red" fill="freeze"	/>
    	</path>  
    	       <path id="L9" transform="translate(-420 -110) scale(1.6)" stroke="crimson"  stroke-dasharray="192" stroke-dashoffset="192" d="m800.1 130.1v52q0 1.2 0.8 1.8 1.2 0.9 3 0.9h8.1v3.1h-30v-3.1h6.9q2.2 0 3.2-1 1-1 1-2.7v-39.3q0-1.2-1-2-1-0.8-2.5-0.8h-9.2v-2.9q6.5-0.8 10.5-2.2 4-1.4 7.1-3.7z"> 
    	  <animate id="an_L9" attributeName="stroke-dashoffset" begin="an_L8.end" dur="0.5s"  values="192;0" fill="freeze"	/>
    	  <animate id="fill_L9" attributeName="fill" begin="fill_L8.end" dur="0.4s"  values="transparent;red" fill="freeze"	/>
    	</path>   
    	
    	    <path id="L10" transform="translate(-420 -110) scale(1.6)" stroke="crimson"  stroke-dasharray="325" stroke-dashoffset="325" d="m854.4 158q-2.7 4.1-6.3 6.2-3.6 2-8.1 2-6.2 0-11.4-4.4-5.1-4.4-5.1-12.9 0-8.3 5.6-14.1 5.7-5.8 13.5-5.8 8.6 0 14.4 7.2 5.8 7.2 5.8 20.1 0 10.8-3.2 18.2-3.2 7.4-8.4 11-5.2 3.6-11.8 3.6-6.4 0-10-2.8-3.6-2.8-3.6-6.7 0-2.6 1.5-4.2 1.5-1.6 3.8-1.6 2 0 3.5 1.4 1.4 1.4 1.4 3.3 0 1.4-1.3 3-0.8 1-0.8 1.8 0 1.2 1.4 2 1.4 0.8 4.4 0.8 4.3 0 7.6-2.4 3.3-2.4 5.3-7.9 2-5.5 2-14.2zm-11.7-26q-4.7 0-7.7 3.9-3 3.9-3 11.7 0 7.2 3 10.7 3 3.5 7.8 3.5 4.8 0 8-3.8 3.3-3.8 3.3-10.6 0-7.1-3.4-11.2-3.4-4.2-8.1-4.2z"> 
    	  <animate id="an_L10" attributeName="stroke-dashoffset" begin="an_L9.end" dur="0.5s"  values="325;0" fill="freeze"	/>
    	  <animate id="fill_L10" attributeName="fill" begin="fill_L9.end" dur="0.4s"  values="transparent;red" fill="freeze"	/>
    	</path>  
    	
    	    <path id="L11" transform="translate(90 0) " stroke="yellowgreen"  stroke-dasharray="279" stroke-dashoffset="279" d="m893.8 126.3h47.6l0.8 21.2h-2.9q-2-11.8-6.1-15-4.2-3.1-10.5-3.1h-8.7q-2.7 0-2.7 2.8v48.8q0 2.2 1 3 1 0.8 3.4 0.8h6.4v3.1h-28.2v-3.1h5q3.5 0 3.5-3.3v-49q0-3.1-3.8-3.1h-4.7z"> 
    	  <animate id="an_L11" attributeName="stroke-dashoffset" begin="an_L10.end" dur="0.5s"  values="279;0" fill="freeze"	/>
    	  <animate id="fill_L11" attributeName="fill" begin="fill_L10.end" dur="0.4s"  values="transparent;greenyellow" fill="freeze"	/>
    	</path>    
    	
    	    <path id="L12" transform="translate(90 0)" stroke="#00C4FF"  stroke-dasharray="346" stroke-dashoffset="346" d="m975.4 125q7.8 0 14.6 4.1 6.8 4.1 10.7 11.5 3.9 7.3 3.9 16.5 0 9.2-3.9 16.6-3.9 7.4-10.7 11.6-6.7 4.1-14.3 4.1-7.4 0-13.9-4-6.5-4.1-10.5-11.6-3.9-7.6-3.9-16.8 0-9.1 3.8-16.4 3.8-7.3 10.5-11.5 6.6-4.2 13.8-4.2zm0.7 3.2q-8.1 0-13.2 6.8-5 6.8-5 22 0 16.5 5.2 22.9 5.2 6.3 12.8 6.3 5.3 0 9.4-2.9 4-2.9 6.4-9.1 2.4-6.2 2.4-16.4 0-11.1-2.2-17.3-2.2-6.2-6.4-9.2-4.2-3-9.3-3z"> 
    	  <animate id="an_L12" attributeName="stroke-dashoffset" begin="an_L11.end" dur="0.5s"  values="346;0" fill="freeze"	/>
    	  <animate id="fill_L12" attributeName="fill" begin="fill_L11.end" dur="0.4s"  values="transparent;cyan" fill="freeze"	/>
    	</path> 
    	   
    	 
    	    <path id="L13" transform="translate(90 0) " stroke="#ED00FF"  stroke-dasharray="485" stroke-dashoffset="485" d="m1072.8 184.8v18.5h-3.1q-0.4-4.7-1.7-8.2-1.4-3.4-6-5.3-4.5-1.9-9.2-1.9h-24.5q-6.9 0-11.4 3.1-4.5 3.2-4.7 12h-3.1l0.6-18.6q5.3-0.2 8.4-1.9 3.1-1.7 6.4-7.8 3.3-6.1 4.5-14.4 1.2-8.3 1.2-19.3 0-6.7-2-9.3-2-2.6-6-2.6h-0.9v-2.8h51.4v3.1h-4.6q-2.4 0-3.2 1-0.8 1-0.8 4.8v44.3q0 5.3 4.9 5.3zm-17.3-0.3v-55.1h-10.6q-5.1 0-7.1 1.5-2 1.4-2.5 4.2-0.5 2.7-0.9 11.5-0.7 18.2-5 27-4.2 8.8-9.9 11z"> 
    	  <animate id="an_L13" attributeName="stroke-dashoffset" begin="an_L12.end" dur="0.5s"  values="485;0" fill="freeze"	/>
    	  <animate id="fill_L13" attributeName="fill" begin="fill_L12.end" dur="0.4s"  values="transparent;magenta" fill="freeze"	/>
    	</path>  
    	      <path id="L14" transform="translate(90 0) " stroke="yellow"  stroke-dasharray="348" stroke-dashoffset="348" d="m1109.4 125q7.8 0 14.6 4.1 6.8 4.1 10.7 11.5 3.9 7.3 3.9 16.5 0 9.2-3.9 16.6-3.9 7.4-10.7 11.6-6.7 4.1-14.3 4.1-7.4 0-13.9-4-6.5-4.1-10.5-11.6-3.9-7.6-3.9-16.8 0-9.1 3.8-16.4 3.8-7.3 10.5-11.5 6.6-4.2 13.8-4.2zm0.7 3.2q-8.1 0-13.2 6.8-5 6.8-5 22 0 16.5 5.2 22.9 5.2 6.3 12.8 6.3 5.3 0 9.4-2.9 4-2.9 6.4-9.1 2.4-6.2 2.4-16.4 0-11.1-2.2-17.3-2.2-6.2-6.4-9.2-4.2-3-9.3-3z"> 
    	  <animate id="an_L14" attributeName="stroke-dashoffset" begin="an_L13.end" dur="0.5s"  values="348;0" fill="freeze"	/>
    	  <animate id="fill_L14" attributeName="fill" begin="fill_L13.end" dur="0.4s"  values="transparent;gold" fill="freeze"	/>
    	</path>   
    	      <path id="L15" transform="translate(90 0) " stroke="yellowgreen"  stroke-dasharray="610" stroke-dashoffset="610" d="m1144.5 126.3h20.5l18.4 48.7 17-48.7h21v3.1h-5.1q-2.7 0-3.7 0.8-0.9 0.8-0.9 2.8v48.8q0 1.5 1.1 2.3 1.1 0.8 3.9 0.8h4.7v3.1h-28.2v-3.1h5.3q2.3 0 3.3-0.8 1.1-0.9 1.1-2.2v-52.3l-20.4 58.5h-2.8l-21.9-58.3v44.8q0 4 1 6 1 2 2.8 3 1.9 1 6.2 1.3v3.1h-23.2v-3.1q5.7-0.4 7.8-2.5 2-2.1 2-7.4v-42.5q0-1.6-1-2.3-1-0.7-3.6-0.7h-5.2z"> 
    	  <animate id="an_L15" attributeName="stroke-dashoffset" begin="an_L14.end" dur="0.5s"  values="610;0" fill="freeze"	/>
    	  <animate id="fill_L15" attributeName="fill" begin="fill_L14.end" dur="0.4s"  values="transparent;greenyellow" fill="freeze"	/>
    	</path>  
    	      <path id="L16" transform="translate(-510 -93) scale(1.5)" stroke="red"  stroke-dasharray="131" stroke-dashoffset="131" d="m1237.5 169.9h-2.2q0-7.5-0.4-11.2-0.6-6.1-2.1-14.5-1.6-9.3-1.6-12.2 0-3.6 1.5-5.4 1.5-1.8 3.8-1.8 2.5 0 3.9 1.8 1.4 1.7 1.4 5.4 0 3.1-1.7 12.3-1.5 8.1-2 13.4-0.5 5.3-0.6 12.2zm-1 9.1q2.1 0 3.6 1.5 1.5 1.5 1.5 3.6 0 2-1.5 3.5-1.5 1.5-3.6 1.5-2.1 0-3.6-1.5-1.5-1.5-1.5-3.6 0-2.2 1.5-3.6 1.5-1.5 3.6-1.5z"> 
    	  <animate id="an_L16" attributeName="stroke-dashoffset" begin="an_L15.end" dur="0.5s"  values="131;0" fill="freeze"	/>
    	  <animate id="fill_L16"   attributeName="fill" begin="fill_L5.end" dur="0.4s"  values="transparent;crimson" fill="freeze"	/>
    	</path> 
    	</g>
    	</g>
    	</svg>
    	</div>

    #2 Анимация волной

    Подробно теория и примеры, как это сделать здесь

    svg {
      background-image: url(https://isstatic.askoverflow.dev/ZNCaY.jpg);
      background-size:cover;
      width:50%
      height:50%
      }
     </style>
     <svg   viewBox="0 0 650 500">
    	
    <defs> 
     <path id="Lsvg" d="M100 200Q200,200 300,200 T500,200" style="stroke:teal;fill-opacity:0.3;stroke-width:3;fill:none;filter:url(#shadow);">
    <animate begin="0.5s"
    dur="10s"
    repeatCount="indefinite"
    restart="whenNotActive"
    attributeName="d" 
    values="M100 200Q200,200 300,200 T500,200;
    M100 200Q200,100 300,200 T500,200;
    M100 200Q200,200 300,200 T500,200;
    M100 200Q200,300 300,200 T500,200;
    M100 200Q200,200 300,200 T500,200"/> 
    </path>
    <filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
                <feDropShadow dx="4" dy="4" stdDeviation="2"/>
            </filter>
    </defs>
    <text text-anchor="middle" font-size="36" fill="crimson" filter="url(#shadow)">
      <textPath id="result" method="align" spacing="auto" startOffset="50%" xlink:href="#Lsvg"><tspan dy="-20">С Новым 2019 годом!</tspan></textPath>
    <animate
     begin="0s"
     dur="10s"
     repeatCount="indefinite"
     attributeName="fill"
     values="purple;yellowgreen;yellow;red;cyan;purple"/>
    </text>
    <use xlink:href="#Lsvg" transform="translate(0 -10)"/>
       
      <rect id="animLink" x="100" y="150" width="400" height="60" fill="#E0E0E0" fill-opacity="0.01" stroke="none" />  
    
    	</svg>

    #3 Двойная анимация,- волны и букв на ней

    svg {
      background-image: url(https://isstatic.askoverflow.dev/3ENnq.jpg);
      background-size:cover;
      width:50%
      height:50%
      }
     <svg   viewBox="0 0 650 500">
    	
    <defs> 
     <path transform="translate(-30 100)" id="Lsvg" d="M100 200Q200,200 300,200 T500,200" style="fill:none; stroke:cyan;stroke-opacity:0.4;stroke-width:5;filter:url(#shadow);">
    <!-- Анимация кривой линии (кривой Безье) -->
     <animate begin="0.5s"
    dur="10s"
    repeatCount="indefinite"
    restart="whenNotActive"
    attributeName="d" 
    values="M100 200Q200,200 300,200 T500,200;
    M100 200Q200,100 300,200 T500,200;
    M100 200Q200,200 300,200 T500,200;
    M100 200Q200,300 300,200 T500,200;
    M100 200Q200,200 300,200 T500,200"/> 
    <!-- Анимация изменения цвета строки--> 
    <animate
     begin="0s"
     dur="14s"
     repeatCount="indefinite"
     attributeName="stroke"
     values="purple;yellowgreen;yellow;#D05589;#D05589;cyan;purple"/>
    </path>
            <filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
                <feDropShadow dx="4" dy="4" stdDeviation="2"/>
            </filter>
        
    
    
    </defs>
    <text text-anchor="middle" font-size="42" fill="purple" filter="url(#shadow)" >
      <textPath id="result" method="align" spacing="auto" startOffset="-48%" xlink:href="#Lsvg"><tspan dx="0" dy="-20">С Новым 2019 годом!</tspan>
     <!-- Движение фразы вдоль кривой линии -->  
      <animate
       dur="15s"
       repeatCount="indefinite"
       attributeName="startOffset"
       values="150%;50%;50%;50%;50%;50%;50%;50%;-50%"/> 
    </textPath>
     
    <!-- Анимация изменения цвета --> 
    <animate
     begin="0s"
     dur="14s"
     repeatCount="indefinite"
     attributeName="fill"
     values="purple;yellowgreen;yellow;#D05589;#D05589;cyan;purple"/>
    </text>
    <use xlink:href="#Lsvg" transform="translate(0 -10)"/>
       
      <rect id="animLink" x="100" y="150" width="400" height="60" fill="#E0E0E0" fill-opacity="0.01" stroke="none" />  
    
    	</svg>

    • 20
  8. UModeL
    2020-12-31T20:52:27Z2020-12-31T20:52:27Z

    Дед Мороз и ёлка

    Это внеконкурсный ответ

    Только HTML и CSS.

    * {
      margin: 0;
      box-sizing: border-box;
      padding: 0;
    }
    
    body {
      background-color: rgb(25, 25, 105);
    }
    
    .wrap_hy {
      margin: 0 auto;
      width: 615px;
      height: 615px;
      overflow: hidden;
    }
    
    .yolka {
      --size: 160px;
      position: relative;
      width: calc(var(--size) * 2.647);
      height: calc(var(--size) * 1);
      font-size: 0;
    }
    
    .zvezda {
      width: 0;
      height: 0;
      margin: 0% 50%;
      color: #fc2e5a;
      position: relative;
      display: block;
      border-right: 100px solid transparent;
      border-bottom: 70px solid #fc2e5a;
      border-left: 100px solid transparent;
      transform: translate(-51%, 15%) scale(-0.4, 0.4) rotate(35deg);
    }
    
    .zvezda:before {
      content: "";
      height: 0;
      width: 0;
      position: absolute;
      display: block;
      top: -45px;
      left: -65px;
      border-bottom: 80px solid #fc2e5a;
      border-left: 30px solid transparent;
      border-right: 30px solid transparent;
      transform: rotate(-35deg);
    }
    
    .zvezda:after {
      content: "";
      width: 0;
      height: 0;
      position: absolute;
      display: block;
      top: 3px;
      left: -105px;
      color: #fc2e5a;
      border-right: 100px solid transparent;
      border-bottom: 70px solid;
      border-left: 100px solid transparent;
      transform: rotate(-70deg);
    }
    
    ul {
      --luchi-flash: 0.3;
      position: absolute;
      z-index: -10;
      left: 50%;
      top: 28%;
      padding: 0;
      width: 0;
      height: 0;
      list-style: none;
      animation: luchi_rotate 10s infinite linear;
    }
    
    li,
    li:before,
    li:after {
      position: absolute;
      width: 0;
      height: 0;
      font-size: 40px;
      border: 0 solid transparent;
      border-width: 1.2em 20em;
      border-color: transparent rgba(255, 193, 7, var(--luchi-flash));
      animation: luchi_flash 4s infinite 0s ease;
    }
    
    li {
      left: -20em;
      top: 50%;
      margin-top: -1.2em;
      transform: rotate(0.1deg);
    }
    
    li:before,
    li:after {
      content: "";
      left: -20em;
      top: -1.2em;
      display: block;
    }
    
    li:before {
      transform: rotate(60deg);
    }
    
    li:after {
      transform: rotate(-60deg);
    }
    
    li:nth-child(2) {
      transform: rotate(15deg);
    }
    
    li:nth-child(2),
    li:nth-child(2):before,
    li:nth-child(2):after {
      border-color: transparent rgba(244, 94, 4, var(--luchi-flash));
      animation: luchi_flash 4s infinite 1s ease;
    }
    
    li:nth-child(3) {
      transform: rotate(30deg);
    }
    
    li:nth-child(3),
    li:nth-child(3):before,
    li:nth-child(3):after {
      border-color: transparent rgba(147, 251, 25, var(--luchi-flash));
      animation: luchi_flash 4s infinite 2s ease;
    }
    
    li:nth-child(4) {
      transform: rotate(45deg);
    }
    
    li:nth-child(4),
    li:nth-child(4):before,
    li:nth-child(4):after {
      border-color: transparent rgba(156, 39, 176, var(--luchi-flash));
      animation: luchi_flash 4s infinite 2s ease;
    }
    
    @keyframes luchi_rotate {
      100% {
        transform: rotate(360deg);
      }
    }
    
    @keyframes luchi_flash {
      0%,
      100% {
        --luchi-flash: 0.2;
      }
      50% {
        --luchi-flash: 0.5;
      }
    }
    
    .yarus {
      position: absolute;
      left: 50%;
      transform: translate(-50%, 0%);
      height: 40%;
      width: 30%;
    }
    
    .yarus:nth-child(2) {
      z-index: -1;
      left: 50%;
      transform: translate(-50%, 40%);
      height: 70%;
      width: 50%;
    }
    
    .yarus:nth-child(3) {
      z-index: -2;
      left: 50%;
      transform: translate(-50%, 80%);
      height: 100%;
      width: 80%;
    }
    
    .yarus:nth-child(4) {
      z-index: -3;
      left: 50%;
      transform: translate(-50%, 160%);
      height: 100%;
      width: 100%;
    }
    
    .yarus div {
      display: inline-block;
      height: 100%;
      width: 50%;
      border-radius: 0 0 0% 100% / 0 0 0% 66%;
      background-image: radial-gradient( circle closest-corner at 34% -68%, transparent 117%, #fbfbfb 122%, #808080 140%, #015001 141%);
      box-shadow: inset 0 calc(var(--size) * -0.3) calc(var(--size) * 0.2) calc(var(--size) * -0.15) rgba(0, 0, 0, 0.5);
    }
    
    .yarus div:nth-child(2) {
      transform: scaleX(-1);
    }
    
    .stvol {
      position: absolute;
      z-index: -5;
      left: 50%;
      transform: translate(-50%, 330%) perspective(200px) rotateX(45deg);
      height: 70%;
      width: 15%;
      border-radius: 15%;
      background: #795548;
      box-shadow: inset 0 calc(var(--size) * -0.1) calc(var(--size) * 0.3) calc(var(--size) * -0.1) white, inset 0 calc(var(--size) * 0.34) calc(var(--size) * 0.4) black;
    }
    
    .girlyanda div {
      position: absolute;
      left: 50%;
      transform: translate(-43%, 56%) rotate(19deg);
      height: 40%;
      width: 40%;
      border-radius: 0 0 50% 50% / 0 0 95% 95%;
      border: 12px dotted;
      border-top: none;
      box-shadow: 0px 10px 30px -25px;
      animation: girlyanda 2.1s ease-in infinite;
      animation-delay: 0s;
    }
    
    .girlyanda div:before {
      content: "";
      position: absolute;
      z-index: -1;
      height: 100%;
      width: 100%;
      border-radius: 0 0 50% 50% / 0 0 95% 95%;
      border: 2px solid #444;
      border-top: none;
    }
    
    .girlyanda div:nth-child(2) {
      transform: translate(-42%, 119%) rotate(19deg);
      height: 56%;
      width: 69%;
      animation-delay: 1s;
    }
    
    .girlyanda div:nth-child(3) {
      transform: translate(-48%, 176%) rotate(23deg);
      height: 80%;
      width: 84%;
      animation-delay: 2s;
    }
    
    .girlyanda div:nth-child(4) {
      transform: translate(-42%, 125%) rotate(-51deg);
      height: 35%;
      width: 44%;
      animation-delay: 3s;
    }
    
    .girlyanda div:nth-child(5) {
      transform: translate(-38%, 291%) rotate(-51deg);
      height: 35%;
      width: 68%;
      animation-delay: 4s;
    }
    
    .girlyanda div:nth-child(6) {
      transform: translate(-54%, 283%) rotate(18deg);
      height: 45%;
      width: 67%;
      animation-delay: 5s;
    }
    
    .girlyanda div:nth-child(7) {
      transform: translate(-71%, 304%) rotate(-7deg);
      height: 59%;
      width: 55%;
      animation-delay: 6s;
    }
    
    @keyframes girlyanda {
      0%,
      100% {
        color: rgb(255, 0, 0);
      }
      25% {
        color: rgba(255, 210, 0, 1);
      }
      50% {
        color: rgb(0, 199, 0);
      }
      75% {
        color: rgb(46, 137, 255);
      }
    }
    
    .ded_moroz {
      position: relative;
    }
    
    .shapka {
      position: absolute;
      left: 50%;
      transform: translateX(-50%);
      height: 75px;
      width: 100px;
      border-radius: 100px / 70px;
      background-color: rgb(230, 0, 0);
      box-shadow: inset -3px 0px 13px -3px black;
    }
    
    .shapka:after {
      content: "";
      position: absolute;
      top: 15px;
      left: 50%;
      transform: translateX(-50%);
      height: 75px;
      width: 120px;
      border-radius: 105px / 53px;
      background-color: rgb(230, 230, 230);
      box-shadow: inset -3px 0px 13px -3px black;
    }
    
    .boroda_lico {
      position: absolute;
      top: 36px;
      left: 50%;
      transform: translateX(-50%);
      height: 130px;
      width: 110px;
      border-radius: 55px 55px 60px 60px / 55px 55px 85px 85px;
      background-color: rgb(240, 240, 240);
      box-shadow: inset -3px 0px 13px -3px black;
    }
    
    .boroda_lico:after {
      content: "";
      position: absolute;
      top: -5px;
      left: 50%;
      transform: translateX(-50%);
      height: 80px;
      width: 90px;
      border-radius: 50px / 50px;
      background-color: rgba(255, 214, 195, 1);
      box-shadow: inset 0px 0px 13px -3px black;
    }
    
    .glaz_l {
      position: absolute;
      z-index: 1;
      top: 20px;
      left: 30%;
      height: 15px;
      width: 13px;
      border-radius: 55px 55px 60px 60px / 55px 55px 85px 85px;
      background-color: rgb(21, 21, 21);
      box-shadow: 0px 0px 5px 0px white;
      animation: morganie 5s infinite linear, oglyad_glaza 15s infinite linear;
    }
    
    .glaz_r {
      position: absolute;
      z-index: 1;
      top: 20px;
      right: 30%;
      height: 15px;
      width: 13px;
      border-radius: 55px 55px 60px 60px / 55px 55px 85px 85px;
      background-color: rgb(21, 21, 21);
      box-shadow: 0px 0px 5px 0px white;
      animation: morganie 5s infinite linear, oglyad_glaza 15s infinite linear;
    }
    
    @keyframes morganie {
      0%,
      10%,
      15%,
      100% {
        height: 15px;
        top: 20px;
      }
      11% {
        height: 3px;
        top: 25px;
      }
    }
    
    @keyframes oglyad_glaza {
      0%,
      10%,
      24%,
      100% {
        transform: translateX(0%);
      }
      12%,
      14% {
        transform: translateX(-30%);
      }
      19%,
      21% {
        transform: translateX(20%);
      }
    }
    
    .nos_brovi {
      position: absolute;
      z-index: 1;
      top: 35px;
      left: 50%;
      transform: translateX(-50%);
      height: 26px;
      width: 53px;
      border-radius: 100px / 50px;
      background-color: rgb(255, 168, 168);
      box-shadow: inset -3px 0px 13px -3px black, 0px 2px 10px -3px black;
    }
    
    .nos_brovi:before {
      content: "";
      position: absolute;
      top: -28px;
      left: 15%;
      transform: translateX(-50%) rotate(-25deg);
      height: 10px;
      width: 32px;
      border-radius: 0px 80px / 50px 50px;
      background-color: rgb(230, 230, 230);
      box-shadow: inset 1px -1px 6px -3px black, 0px 2px 10px -3px black;
      animation: oglyad_brovi_l 15s infinite linear;
    }
    
    .nos_brovi:after {
      content: "";
      position: absolute;
      top: -28px;
      right: -45%;
      transform: translateX(-50%) rotate(25deg);
      height: 10px;
      width: 32px;
      border-radius: 80px 0px / 50px 50px;
      background-color: rgb(230, 230, 230);
      box-shadow: inset -1px -1px 6px -3px black, 0px 2px 10px -3px black;
      animation: oglyad_brovi_r 15s infinite linear;
    }
    
    @keyframes oglyad_brovi_l {
      0%,
      10%,
      19%,
      100% {
        transform: translateX(-50%) rotate(-25deg);
      }
      13%,
      16% {
        transform: translateX(-50%) rotate(0deg);
      }
    }
    
    @keyframes oglyad_brovi_r {
      0%,
      17%,
      25%,
      100% {
        transform: translateX(-50%) rotate(25deg);
      }
      20%,
      22% {
        transform: translateX(-50%) rotate(0deg);
      }
    }
    
    .rot_usw {
      position: absolute;
      z-index: 1;
      top: 80px;
      left: 50%;
      transform: translateX(-50%);
      height: 26px;
      width: 53px;
    }
    
    .rot_usw:before {
      content: "";
      position: absolute;
      top: -28px;
      left: -5%;
      transform: translateX(-50%) rotate(-40deg);
      height: 32px;
      width: 50px;
      border-radius: 0px 80px / 50px 50px;
      background-color: rgb(230, 230, 230);
      box-shadow: inset 1px -1px 6px -3px black, 0px 2px 10px -3px black;
    }
    
    .rot_usw:after {
      content: "";
      position: absolute;
      top: -28px;
      right: -105%;
      transform: translateX(-50%) rotate(40deg);
      height: 32px;
      width: 50px;
      border-radius: 80px 0px / 50px 50px;
      background-color: rgb(230, 230, 230);
      box-shadow: inset -1px -1px 6px -3px black, 0px 2px 10px -3px black;
    }
    
    .tulup {
      position: absolute;
      top: 100px;
      left: 50%;
      transform: translateX(-50%);
      height: 355px;
      width: 240px;
      border-radius: 40% 40% 10% 10%;
      background-color: rgb(230, 0, 0);
      box-shadow: inset -13px 0px 73px -3px black;
    }
    
    .tulup:before {
      content: "";
      position: absolute;
      bottom: -10px;
      left: 50%;
      transform: translateX(-50%);
      height: 35px;
      width: 250px;
      border-radius: 20% 20% 40% 40%;
      background-color: rgb(230, 230, 230);
      box-shadow: inset -23px 0px 53px -15px black;
    }
    
    .tulup:after {
      content: "";
      position: absolute;
      z-index: -2;
      bottom: -10px;
      left: 50%;
      transform: translateX(-50%);
      height: 350px;
      width: 25px;
      border-radius: 20% 20% 40% 40%;
      background-color: rgb(230, 230, 230);
      box-shadow: 1px -10px 16px -5px black;
    }
    
    .plecho_l {
      position: absolute;
      top: 40px;
      left: 0px;
      height: 140px;
      width: 70px;
      border-radius: 100% 60% 55px 55px;
      background-color: rgb(230, 0, 0);
      box-shadow: inset 0px -10px 53px -15px black, 1px 10px 16px -5px black;
    }
    
    .plecho_r {
      position: absolute;
      top: 40px;
      right: 0px;
      height: 140px;
      width: 70px;
      border-radius: 60% 100% 55px 55px;
      background-color: rgb(230, 0, 0);
      box-shadow: inset -15px -10px 53px -15px black, 1px 10px 16px -5px black;
    }
    
    .lokot_l {
      position: absolute;
      bottom: 0px;
      left: 0px;
      height: 70px;
      width: 100px;
      border-radius: 100% 60% 55px 55px;
      background-color: rgb(230, 0, 0);
      box-shadow: inset 0px -10px 53px -15px black, 1px 10px 16px -5px black;
    }
    
    .lokot_l:after {
      content: "";
      position: absolute;
      top: 50%;
      right: 0px;
      transform: translateY(-50%);
      height: 80px;
      width: 30px;
      border-radius: 35%;
      background-color: rgb(230, 230, 230);
      box-shadow: inset 0px -10px 53px -15px black, 1px 10px 16px -5px black;
    }
    
    .lokot_r {
      position: absolute;
      bottom: 0px;
      right: 0px;
      height: 70px;
      width: 100px;
      border-radius: 60% 100% 55px 55px;
      background-color: rgb(230, 0, 0);
      box-shadow: inset -15px -10px 53px -15px black, 1px 10px 16px -5px black;
    }
    
    .lokot_r:after {
      content: "";
      position: absolute;
      top: 50%;
      left: 0px;
      transform: translateY(-50%);
      height: 80px;
      width: 30px;
      border-radius: 35%;
      background-color: rgb(230, 230, 230);
      box-shadow: inset 0px -10px 53px -15px black, 1px 10px 16px -5px black;
    }
    
    .kist_l {
      position: absolute;
      z-index: -1;
      top: 5px;
      right: -30px;
      height: 60px;
      width: 60px;
      border-radius: 100% 60% 55px 55px;
      background-color: rgba(255, 214, 195, 1);
      box-shadow: inset 0px -10px 53px -15px black, 1px 10px 16px -5px black;
    }
    
    .kist_r {
      position: absolute;
      z-index: -1;
      top: 0px;
      left: -30px;
      height: 60px;
      width: 60px;
      border-radius: 60% 100% 55px 55px;
      background-color: rgba(255, 214, 195, 1);
      box-shadow: inset -15px -10px 53px -15px black, 1px 10px 16px -5px black;
    }
    <div class="wrap_hy">
      <div class="yolka">
        <div class="zvezda">
          <div class="zvezda">
          </div>
        </div>
        <div class="yarus">
          <div></div>
          <div></div>
        </div>
        <div class="yarus">
          <div></div>
          <div></div>
        </div>
        <div class="yarus">
          <div></div>
          <div></div>
        </div>
        <div class="yarus">
          <div></div>
          <div></div>
        </div>
        <div class="stvol">
          <div></div>
          <div></div>
        </div>
        <div class="girlyanda">
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
          <div></div>
        </div>
        <ul class="luchi">
          <li></li>
          <li></li>
          <li></li>
          <li></li>
        </ul>
      </div>
      <div class="ded_moroz">
        <div class="telo">
          <div class="tulup">
            <div class="plecho_l">
              <div class="lokot_l">
                <div class="kist_l">
                </div>
              </div>
            </div>
            <div class="plecho_r">
              <div class="lokot_r">
                <div class="kist_r">
                </div>
              </div>
            </div>
          </div>
        </div>
        <div class="golova">
          <div class="shapka"></div>
          <div class="boroda_lico">
            <div class="glaz_l"></div>
            <div class="glaz_r"></div>
            <div class="rot_usw"></div>
            <div class="nos_brovi"></div>
          </div>
        </div>
      </div>
    </div>

    • 19
  9. Stranger in the Q
    2020-01-04T18:44:42Z2020-01-04T18:44:42Z

    d3.js 🎄 интерактивная версия

    никаких внешних ресурсов не использовано

    在此处输入图像描述

    updates 06.01.2019:

    • можно перетащить игрушки на елку, чтобы они замигали
    • теперь падает снег и есть сугробы
    • добавлены фильтры для придания плавных переходов между фигугами и для придания псевдо объема игрушкам

    updates 08.01.2019:

    • появляется текст

    <!DOCTYPE html>
    <html lang="en">
    <body style="margin: 0">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
    <style>
        .text-effect {
            overflow: hidden;
            position: absolute;
            width: 620px;
            margin-left: calc(50vw - 310px);
            top: calc(50vh - 300px);
            -webkit-filter: contrast(110%) brightness(190%);
            filter: contrast(110%) brightness(190%);
        }
        .neon {
            position: relative;
            background: black;
            color: transparent;
            width: 100%;
            text-align: center;
        }
        .neon::before, .neon::after {
            content: attr(data-text);
            color: white;
            -webkit-filter: blur(0.02em);
            filter: blur(0.02em);
            position: absolute;
            top: 0;
            left: 0;
            pointer-events: none;
        }
        .neon::after {
            mix-blend-mode: difference;
        }
        .gradient, .spotlight {
            position: absolute;
            top: 0;
            left: 0;
            bottom: 0;
            right: 0;
            pointer-events: none;
            z-index: 10;
        }
        .gradient {
            background: linear-gradient(45deg, #f9ff09, #ff00f9);
            mix-blend-mode: multiply;
        }
        .spotlight {
            -webkit-animation: light 5s infinite linear;
            animation: light 5s infinite linear;
            background: radial-gradient(circle, white, transparent 25%) 0 0/25% 25%,
                        radial-gradient(circle, white, black 25%) 50% 50%/12.5% 12.5%;
            top: -100%;
            left: -100%;
            mix-blend-mode: color-dodge;
        }
    
        @-webkit-keyframes light {
            100% {
                -webkit-transform: translate3d(50%, 50%, 0);
                transform: translate3d(50%, 50%, 0);
            }
        }
    
        @keyframes light {
            100% {
                -webkit-transform: translate3d(50%, 50%, 0);
                transform: translate3d(50%, 50%, 0);
            }
        }
        .neon {
            font: 700 220px sans-serif;
            text-transform: uppercase;
            text-align: center;
            margin: 0;
        }
        .neon:focus {
            outline: none;
        }
    </style>
    
    <div class="text-effect" style="display: none; position: fixed; mix-blend-mode: lighten;">
        <h1 class="neon" data-text="20&nbsp;&nbsp;19" contenteditable>20&nbsp;&nbsp;19</h1>
        <div class="gradient"></div>
        <div class="spotlight"></div>
    </div>
    
    <script>
        var w = 800, h = 600;
        var c = [w / 2, h / 2 + 100];
        var svg = appendSvg();
        var defs = svg.append('defs');
    
        filter_smoothMin('smin');
        filter_3d('3d');
    
        hills();
        tree();
        toys();
        snow();
    
        function snow() {
            var snowFlakes = svg.append('g')
                .style('filter', 'url(#smin)')
                .selectAll('.snowflake')
                .data(d3.range(100).map(function () {
                    return Math.random() * h
                }))
                .enter()
                .append('circle')
                .classed('.snowflake', true)
                .attr('fill', 'snow')
                .attr('cy', function (d) {
                    return d;
                })
                .each(function (d) {
                    animate(d3.select(this), (1000 + Math.random() * 2000) * (h - d) / h)
                });
    
            setInterval(loopAnimation, 100);
    
            function loopAnimation() {
                snowFlakes.filter(function () {
                    var y = +d3.select(this).attr('cy');
                    return y >= 600 || !y;
                }).attr('cy', -30).each(function () {
                    animate(d3.select(this), 1000 + Math.random() * 2000);
                })
            }
    
            function animate(selection, t) {
                selection
                    .attr('cx', function (d) {
                        return Math.random() * w;
                    })
                    .attr('r', function () {
                        return 3 + Math.random() * 3;
                    })
                    .transition()
                    .duration(t)
                    .ease(d3.easeLinear)
                    .attr('cx', function (d) {
                        return +selection.attr('cx') +
                            Math.random() * 100 * Math.sign(Math.random() - 0.5);
                    })
                    .attr('cy', h);
            }
        }
    
        function hills() {
            svg.append('g')
                .style('filter', 'url(#smin)')
                .selectAll('circle')
                .data(d3.range(0, 10).map(function (i) {
                    return 1500 - i * 100 + h / 2;
                }))
                .enter()
                .append('circle')
                .attr('cx', function (d) {
                    return w * 2 * Math.random() - w;
                })
                .attr('cy', function (d) {
                    return d + h / 2;
                })
                .attr('r', function (d) {
                    return d;
                })
                .attr('fill', '#f2f2f2')
                .attr('stroke-width', '1')
                .attr('stroke', 'steelblue')
        }
    
        function tree() {
    
            bark();
            level(0);
            level(1);
            level(2);
    
            function bark() {
                svg.append('path')
                    .attr('d', m(20, 40) + l(20, 70) + l(0, 80) + l(0, 50))
                    .attr('fill', '#5B3413');
    
                svg.append('path')
                    .attr('d', m(-20, 40) + l(-20, 70) + l(0, 80) + l(0, 50))
                    .attr('fill', 'brown');
            }
    
            function level(i) {
                var s = 100 - i * 20;
                var g = svg.append('g')
                    .style('filter', 'url(#smin)');
    
                path(m(0, s / 2) + l(-s, 0) + l(0, -s * 2))
                    .attr('fill', 'lightgreen');
    
                path(m(0, s / 2) + l(s, 0) + l(0, -s * 2))
                    .attr('fill', 'green');
    
                path(m(s, 0) + l(0, s / 2) + l(-s, 0)).attr('stroke', 'white')
                    .attr("fill", "none")
                    .attr('stroke-linejoin', 'round')
                    .attr('stroke-linecap', 'round')
                    .attr('stroke-width', '12');
    
                function path(d) {
                    return g.append('path')
                        .attr('transform', 'translate(0 ' + (-i * 100) + ') ')
                        .attr('d', d);
                }
            }
        }
    
        function toys() {
            var color = d3.scaleOrdinal(d3.schemeCategory10);
    
            var toys = d3.range(0, 9).map(function (i) {
                return {
                    x: 50 + Math.random() * (w - 100),
                    y: h - 125 + Math.random() * 100,
                    shape: i % d3.symbols.length,
                    color: color(Math.random() * 10),
                    angle: Math.random() * 360
                }
            });
    
            var symbols = svg.append('g')
                .classed('toys', true)
                .style('filter', 'url(#3d)')
                .selectAll('.symbol')
                .data(toys)
                .enter()
                .append('path')
                .classed('symbol', true)
                .attr('cursor', 'pointer')
                .attr('transform', translate)
                .attr('stroke', 'black')
                .attr('stroke-width', '0')
                .attr('fill', "gray")
                .attr('d', d3.symbol().size(function () {
                    return 512 + Math.random() * 512;
                }).type(function (d, i) {
                    return d3.symbols[i % d3.symbols.length];
                }))
                .each(dragged)
                .call(d3.drag()
                    .on("start", dragstarted)
                    .on("drag", dragged)
                    .on("end", dragended));
    
            function dragstarted(d) {
                d3.select(this)
                    .classed('active', true)
                    .raise()
                    .attr("transform", translate)
                    .attr("stroke-width", 2);
    
            }
    
            function dragged(d) {
                if (d3.event) {
                    d.x = d3.event.x;
                    d.y = d3.event.y;
                }
                d3.select(this)
                    .attr("transform", translate)
                    .attr("fill", check(d) ? d.color : "gray");
            }
    
            function translate(d) {
                var scale = d3.select(this).classed('active') ? " scale(1.3)" : "";
                return "rotate(" + d.angle + " " + d.x + " " + d.y + ") " +
                    "translate(" + d.x + "," + d.y + ")" + scale;
            }
    
            function dragended() {
                d3.select(this)
                    .classed('active', false)
                    .attr("transform", translate)
                    .attr("stroke-width", 0);
                var left = [];
                symbols.filter(function (d) {
                    !check(d) && left.push(d);
                });
                repeat(left.length)
            }
    
            function repeat(stop) {
                d3.select('.text-effect').style('display', stop ? 'none' : 'block')
    
                var transition = symbols.transition()
                    .attr("fill", function (d) {
                        return check(d) ? d.color : "gray"
                    });
                
                if (stop)
                    return;
    
                transition
                    .attr('fill', function () {
                        return color(Math.random() * 10);
                    })
                    .ease(d3.easeLinear)
                    .duration(1000)
                    .attr('fill', function () {
                        return color(Math.random() * 10);
                    })
                    .on('end', function () {
                        repeat(false)
                    })
    
    
            }
    
            function check(d) {
                return d.x < 500 && d.x > 300 && d.y < 450 && d.y > 75;
            }
        }
    
        function l(x, y) {
            return "L" + p(x, y)
        }
    
        function m(x, y) {
            return "M" + p(x, y)
        }
    
        function p(x, y) {
            return (c[0] + x) + "," + (c[1] + y) + " ";
        }
    
        function filter_smoothMin(id) {
            // https://tympanus.net/codrops/2015/03/10/creative-gooey-effects/
            var filter = defs.append('filter')
                .attr('id', id);
    
            filter.append('feGaussianBlur')
                .attr('in', 'SourceGraphic')
                .attr('stdDeviation', '3')
                //to fix safari: http://stackoverflow.com/questions/24295043/svg-gaussian-blur-in-safari-unexpectedly-lightens-image
                .attr('color-interpolation-filters', 'sRGB')
                .attr('result', 'blur');
    
            filter.append('feColorMatrix')
                .attr('in', 'blur')
                .attr('mode', 'matrix')
                .attr('values', '1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 19 -9')
        }
    
        function filter_3d(id) {
            // https://www.w3.org/TR/SVGFilterPrimer12/
            var filter = defs.append('filter')
                .attr('id', id)
                .attr('filterUnits', 'userSpaceOnUse')
                .attr('x', 0)
                .attr('y', 0)
                .attr('width', w)
                .attr('height', h);
    
            filter.append('feGaussianBlur')
                .attr('in', 'SourceAlpha')
                .attr('stdDeviation', 4)
                .attr('result', "blur");
    
            filter.append('feSpecularLighting')
                .attr('in', 'blur')
                .attr('surfaceScale', 5)
                .attr('specularConstant', .75)
                .attr('specularExponent', 20)
                .attr('lighting-color', "#bbbbbb")
                .attr('result', "specOut")
                .append('fePointLight')
                .attr('x', -5000)
                .attr('y', -10000)
                .attr('z', 20000);
    
            filter.append('feComposite')
                .attr('in', 'specOut')
                .attr('in2', 'SourceAlpha')
                .attr('operator', 'in')
                .attr('result', "specOut");
    
            filter.append('feComposite')
                .attr('in', 'SourceGraphic')
                .attr('in2', 'specOut')
                .attr('operator', 'arithmetic')
                .attr('k1', 0)
                .attr('k2', 1)
                .attr('k3', 1)
                .attr('k4', 0)
                .attr('result', "litPaint");
        }
    
        function appendSvg() {
            return d3.select('body').append('svg')
                .style('margin-left', 'calc(50vw - ' + w / 2 + 'px)')
                .style('margin-top', 'calc(50vh - ' + h / 2 + 'px)')
                .style('background-color', 'steelblue')
                .attr('width', w).attr('height', h)
                .attr('viewBox', '0 0 ' + w + ' ' + h)
        }
    </script>
    </body>
    </html>

    • 18
  10. Ver Nick
    2020-01-02T04:32:58Z2020-01-02T04:32:58Z

    Начну делать елку с звезды. Я сделал лучи заднего плана полностью на линейных градиентах без svg. Звезду позаимстовал у SE и добавил эффект свечения. Получилось вот что-то такое:

    html, body {
      width: 100%;
      height: 100%;
      margin: 0;
      background-color: lightgreen;
    }
    #star_back {
      position: relative;
      width: 100%;
      height: 100%;
    }
    #star_back:after, #star_back:before {
      content: '';
      position: absolute;
      background: linear-gradient(90deg, transparent 50%, black 50%, black), linear-gradient(82deg, transparent 50%, lightgreen 50%, lightgreen), linear-gradient(67deg, transparent 50%, green 50%, green), linear-gradient(52deg, transparent 50%, lightgreen 50%, lightgreen), linear-gradient(37deg, transparent 50%, green 50%, green), linear-gradient(22deg, transparent 50%, lightgreen 50%, lightgreen), linear-gradient(7deg, transparent 50%, green 50%, green), linear-gradient(-8deg, transparent 50%, lightgreen 50%, lightgreen), linear-gradient(-23deg, transparent 50%, green 50%, green), linear-gradient(-38deg, transparent 50%, lightgreen 50%, lightgreen), linear-gradient(-53deg, transparent 50%, green 50%, green), linear-gradient(-68deg, transparent 50%, lightgreen 50%, lightgreen), linear-gradient(-83deg, transparent 50%, green 50%, green), linear-gradient(-90deg, transparent 50%, lightgreen 50%, lightgreen), radial-gradient(transparent 90%, white 10%);
      background-position: 0% 0%;
      background-size: 200% 100%;
      height: 200px;
      width: 120px;
      border-top-left-radius: 50%;
      border-bottom-left-radius: 50%;
    
    }
    #star_back:before {
      left: 120px;
      transform: rotate(180deg);
    }
    #star_gradient{
      background: radial-gradient(transparent, lightgreen);
        width: 240px;
        height: 220px;
        z-index: 1;
        position: absolute;
    }
    #star{
      width: 80px;
      height: 80px;
      margin-left: 80px;
      margin-top: 60px;
      opacity: 1;
    -webkit-filter: drop-shadow( -5px -5px 5px gold ); 
            filter: drop-shadow( 0px 0px 10px gold );
    }
    <div id="star_back"><div id = "star_gradient"><svg aria-hidden="true" width="18" height="18" viewBox="0 0 18 18" id = "star"><path d="M9 12.65l-5.29 3.63 1.82-6.15L.44 6.22l6.42-.17L9 0l2.14 6.05 6.42.17-5.1 3.9 1.83 6.16z" fill="gold"></path></svg></div></div>

    • 17

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    是否可以在 C++ 中继承类 <---> 结构?

    • 2 个回答
  • Marko Smith

    这种神经网络架构适合文本分类吗?

    • 1 个回答
  • Marko Smith

    为什么分配的工作方式不同?

    • 3 个回答
  • Marko Smith

    控制台中的光标坐标

    • 1 个回答
  • Marko Smith

    如何在 C++ 中删除类的实例?

    • 4 个回答
  • Marko Smith

    点是否属于线段的问题

    • 2 个回答
  • Marko Smith

    json结构错误

    • 1 个回答
  • Marko Smith

    ServiceWorker 中的“获取”事件

    • 1 个回答
  • Marko Smith

    c ++控制台应用程序exe文件[重复]

    • 1 个回答
  • Marko Smith

    按多列从sql表中选择

    • 1 个回答
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Suvitruf - Andrei Apanasik 什么是空? 2020-08-21 01:48:09 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5