Страницы

Поиск по вопросам

воскресенье, 24 ноября 2019 г.

Анимация новогодней ёлочки


Наступает Новый год!

Хорошо бы поднять настроение себе и другим. 
Копировать и рассылать открыточки с красивыми картинками и гифками, скаченными и
сети, уже как-то не интересно. 

Хочется чего-то необычного, яркого, праздничного, которое есть только у тебя и которо
можно подарить близкому человеку со словами,- "Я сделал это для тебя!"
или оставить  у себя с чувством удовлетворения и гордости :-)   

Идея сделать новогодний конкурс анимаций принадлежит @Hamster  

Вот и рисунок, который она дала для образца.



Смотрите, как и в любой другой новогодней открытке, тут есть потенциал для всевозможны
 анимаций. 

Например: 


Лучи от звезды.


Можно легко сделать с помощью stroke-dasharray для широкой строки. Добавить радиальны
градиент, анимацию вращения строки и перемещения градиента.


Снежинки     


Нарисовать  в CSS или в SVG многие смогут и далее за анимировать размеры, вращение
падение снежинок. 


Елочка
Перемигивание гирлянд, легкое покачивание и кручение елочных игрушек, бенгальски
огни и т.д и т.п  
Анимация фразы - С Новым 2019 годом!  

движение фразы и/или покачивание, обводка, появление букв 
Анимация новогодних персонажей,- белочки, зайчики :) Дед мороз и
снегурочка   


Можно делать весь вышеперечисленный список анимаций, можно реализовать один пунк
или несколько.   

Главное условие - картинки можно брать любые или рисовать свои, но анимация должн
быть своя, никакого копи-паста! 

Конкурс завершился.   

Поздравляю победителя @Misha Saidov

Благодаря вашим работам дорогие участники, конкурс получился интересным, ярким, запоминающимся
Мы вместе узнали имена новых участников, которые сразу, с ходу ворвались в конкурс 
сделали очень крутые работы.
Все работы сделаны на высоком уровне и каждая по своему интересна и хороша. 
    


Ответы

Ответ 1



ВНИМАНИЕ! Ёлка не идеальна и только для современных браузеров и только в качестве примера! 🎄 ПРИМЕР НА 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; }
< class="c-3">
< class="c-7">
Пришлось обратится за помощью, но потом и меня осенила собственная идея: 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. ❄ ❄ ❄ ❄ ❄ ❄ ❄ С наступающим Новым Годом! Мира всем и добра! ❄ ❄ ❄ ❄ ❄ ❄ ❄

Ответ 2



Это бандл из моих предыдущих ответов. Как видите, код стал модульным - можно на его базе собрать любого Франкенштейна Также код вариативный везде, где только можно - любой коэффициент можно поменять, чтоб добиться желаемого результата и резиновый (на сколько смог). Повторюсь, что я не умею в векторную графику и канвас, поэтому накодил все на дивах и картинках. Разверните на всю страницу, если сильно сплющит. 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 = $(""); 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(""); } let star = $(""); 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 = $("
"); 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 === " " ? " " : char; let charElem = $("
" + char + "
"); 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; }


Ответ 3



Всех с наступающим!! Сцена создана без использования каких-либо ресурсов. Только математика. Запаситесь видеокартой, тут процессор не делает почти совсем ничего, фрагментный шейдер тут больше чем в 400 строчек получился =) Это все придумано давным давно, однако раньше, трассировка лучей в реальном времен была фантастикой и таким образом создавали статические картинки. сегодня каждый обладатель компьютера с видеокартой может написать фрагментный шейдер, который делает трассировку простеньких (и не очень) сцен в реальном времени. Для этого потребуются: Желание разбираться с математикой Много свободного времени Видеокарта, у меня gtx1050ti (768 вычислительных ядер) и это мало :( Браузер с поддержкой WebGL Во фрагменте кода приведена уже склеенная версия, исходник на github gists и blocks. Итак, попробую по-простому описать что тут происходит, т.к. код вы можете и сам почитать. Для начала WebGL инициализируется таким образом, чтобы нарисовать один треугольник который покрывает весь экран как на изображении ниже, или как-то иначе, главное вызвать фрагментный шейдер для каждого пикселя. Для этого я как-то написал себе маленькую утилиту GLx, которая мне помогает сделать это в несколько строк. Фрагментный шейдер делает всю работу. Перед формированием каждого кадра, из javascript в шейдер передаются некоторые переменные которые характеризуют сцену, в нашей ёлочке это положение наблюдателя в декартовых координатах, размер картинки, и еще для анимации понадобится время. конечно перед каждым кадром обновлять все uniform переменные не нужно, но в это примере я сделал так для простоты кода. Далее в каждом фрагменте(пикселе) происходит трассировка луча В нашем случае это raymarching, что про сути есть оптимизация шага трассировки. В отличие от классического представления объектов сцены в виде треугольников, ту используются математические формулы дистанции до поверхностей. Шагая вдоль луча, применяетс огромная формула (функция 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 и предназначена для объединения объектов сцены. каждый компонент, объединяемый этой операцией это в свою очередь тоже функция, тольк описывающая один объект сцены плюс возвращающая вторым компонентом идентификатор(цвет материала в найденной точке. в свою очередь состят из более простых примитив, сфер, цилиндров, кубов, фракталов, поверхностей безье, чего душе угодно, между которыми возможно всевозможные трансформации, булевые операции итд. все вместе это и описывает нашу сцену с елочкой. после того, как точка пересечения луча с поверхностью найдена, начинается самое сложное и самое интересное, это определение цвета найденной точки в нашей сцене цвет состоит из нескольких компонентов: цвет поверхности (диффузный) модель освещения по Фонгу(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: Где можно про это почитать: Сайт Inigo Quilez. Простенький туториал от Jamie Wong ну и конечно же гуглёж по терминам signed distance field(function), SDF raymarching, raytracing UPD 31.03.2019: Починил ( правда ценой производительности (: ) артефакты прошло версии, когда при взгляде сверху появлялись черно-цветные полосы.

Ответ 4



А вот и Ёлочка! Я плох в векторной графике и канвасе, но что-то смыслю в математике, поэтому ка смог :) В общем, можно заметить, что есть очень много общего со скриптом снежинок, которы я кидал ранее. Соль заключается в том, что позиционированием звездочек полностью занимаетс 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 = $(""); 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; } }


Ответ 5



Начну для затравки. Конкурс откроется сегодня, - 24.12.2018 г. с хорошим вознаграждением. Как раз будем подводить итоги накануне Нового года. Возьмусь, для примера, сделать первый пункт анимации из списка в вопросе. Так как я буду использовать в этой заготовке базовые команды svg и простые, общеизвестны приемы, то можно смело их использовать в конкурсных ответах, это не будет считаться копи-пастом. Лучи от звезды. Я делаю в SVG, естественно возможно это реализовать и на CSS, Javascript, jQuery Как это может быть сделано средствами SVG При радиусе r="100" длина окружности равна 2 * 3,14 * 100 = 628px Нужно получить 12 лучей + 12 промежутков = 24 равные части. Одна часть равна 26,16px Подставляем длину черты и интервала в атрибут Увеличиваем ширину строки до stroke-width="200" Так как строка размещается симметрично по обе стороны от осевой линии окружности и при r="100px" её ширина должна быть 200px для заполнения внутреннего пространства окружности. Для демонстрации окружность заполнена цветом fill="purple" Прототип снежинки Убираем заливку fill="none" и присваиваем stroke="#87CEFA" В центр лучей добавляем звёздочку Добавляем градиент лучей звезды и анимацию, к сожалению анимация в этом варианте работает только в FF Этот кусок кода закомментирован Анимация вращения лучей звезды Для вращения объекта по часовой стрелке на один полный оборот необходимо добавить внутри его тегов команду анимации: Немного сложна семантика тегов объекта при использовании вложенной анимации. Внести ясность поможет топик: Эти странные теги SVG Ниже код анимации вращения лучей звезды Усложняем алгоритм вращения values="0 200 200;720 200 200;720 200 200;0 200 200;0 200 200" Поворот по часовой стрелке на 720 ° → пауза → поворот против часовой стрелк на 720 ° → пауза Подбирая углы, их порядок следования, а также изменяя время вращения dur="3.43s", можно получить интересные эффекты

Ответ 6



Думаю, можно поменьше 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 = $(""); 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); } }


Ответ 7



Варианты анимации фразы - С Новым 2019 годом! Этот вариант не участвует в конкурсе, создан для примера. Участники могут брать эт технику анимации прорисовки и раскрашивания букв в качестве заготовки и использовать, творчески переработав, в своих конкурсных ответах. Как сделать анимацию обводки букв - подробно, с картинками рассказывается как это сделать update Новый вариант
#2 Анимация волной Подробно теория и примеры, как это сделать здесь svg { background-image: url(https://i.stack.imgur.com/ZNCaY.jpg); background-size:cover; width:50% height:50% } С Новым 2019 годом! #3 Двойная анимация,- волны и букв на ней svg { background-image: url(https://i.stack.imgur.com/3ENnq.jpg); background-size:cover; width:50% height:50% } С Новым 2019 годом!

Ответ 8



Дед Мороз и ёлка Это внеконкурсный ответ Только 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; }


Ответ 9



d3.js 🎄 интерактивная версия никаких внешних ресурсов не использовано updates 06.01.2019: можно перетащить игрушки на елку, чтобы они замигали теперь падает снег и есть сугробы добавлены фильтры для придания плавных переходов между фигугами и для придания псевдо объема игрушкам updates 08.01.2019: появляется текст

Ответ 10



Начну делать елку с звезды. Я сделал лучи заднего плана полностью на линейных градиентах без 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, transparen 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 ); }


Ответ 11



Остальное делать время нет...если будет время до рисую до конца весь мультик ка я и задумал .tree { fill: url(#pattern); } .top-star { fill: red; stroke-width: 2; stroke: yellow } .star-tree { opacity: .8; paint-order: markers stroke fill; } .tree-line { fill: none; stroke: #e09a11; stroke-width: 2px; stroke-linecap: butt; stroke-linejoin: miter; stroke-opacity: 1; stroke-miterlimit: 4; stroke-dasharray: 0.26499999, 0.52999997; stroke-dashoffset: 0 } .fill-gray { fill: #ccc; stroke: none; opacity: 0.5; } .green { fill: #00ff00; } .blue { fill: #0000ff; } .pink { fill: #ff5555; } .red { fill: #ff0000; }