Skip to main content
3 of 5
Added a new christmas tree
Mark Wibrow
  • 71.6k
  • 4
  • 154
  • 208

Here's a Christmas tree for 2015:

\documentclass[tikz,border=5]{standalone} \usetikzlibrary{backgrounds,arrows.meta} \pgfdeclarelayer{foreground} \pgfdeclarelayer{before-background} \pgfsetlayers{background,before-background,main,foreground} \usepackage{luacode} \begin{luacode*} floor = math.floor ceil = math.ceil Maze = {} Maze.__index = Maze Maze.NORTH = 90 Maze.SOUTH = 270 Maze.EAST = 0 Maze.WEST = 180 Maze.new = function(r, c) local i, j, row, cell local obj = {} setmetatable(obj, Maze) obj.rows = r obj.cols = c obj:reset() return obj end Maze.reset = function(self) local i, j, row, cell self.cells = {} for i = 1,self.rows do row = {} for j = 1,self.cols do cell = {visited=false, visitable=true, north=true,south=true,east=true, west=true, meta=''} table.insert(row, cell) end table.insert(self.cells, row) end end Maze.visitable = function(self, i, j) return self.cells[i] and self.cells[i][j] and self.cells[i][j].visitable end Maze.isVisitable = function(self, i, j) return self.cells[i] and self.cells[i][j] and self.cells[i][j].visitable end Maze.setVisitable = function(self, i, j, visitable) self.cells[i][j].visitable = visitable self.cells[i][j].north = visitable self.cells[i][j].south = visitable self.cells[i][j].east = visitable self.cells[i][j].west = visitable end Maze.getMeta = function(self, i, j) return self.cells[i][j].meta end Maze.setMeta = function(self, i, j, meta) self.cells[i][j].meta = meta end Maze.create = function(self, start) local n, N, x, y, a, b, k, stack N = self.rows * self.cols for i = 1,self.rows do for j = 1,self.cols do if not self.cells[i][j].visitable then N = N - 1 end end end start = start or {x=1, y=1} x, y = start.x, start.y stack = {} table.insert(stack, {x=x, y=y}) self.cells[y][x].visited = true visited = 1 while visited < N do x = stack[#stack].x y = stack[#stack].y n = {} if self:isVisitable(y+1, x) and not self.cells[y+1][x].visited then table.insert(n, Maze.NORTH) end if self:isVisitable(y-1, x) and not self.cells[y-1][x].visited then table.insert(n, Maze.SOUTH) end if self:isVisitable(y, x+1) and not self.cells[y][x+1].visited then table.insert(n, Maze.EAST) end if self:isVisitable(y, x-1) and not self.cells[y][x-1].visited then table.insert(n, Maze.WEST) end if #n == 0 then table.remove(stack) else k = n[math.random(#n)] if k == Maze.NORTH then a, b = x, y+1 self.cells[y][x].north = false self.cells[b][a].south = false elseif k == Maze.SOUTH then a, b = x, y-1 self.cells[y][x].south = false self.cells[b][a].north = false elseif k == Maze.EAST then a, b = x+1, y self.cells[y][x].east = false self.cells[b][a].west = false elseif k == Maze.WEST then a, b = x-1, y self.cells[y][x].west = false self.cells[b][a].east = false end table.insert(stack, {x=a, y=b}) self.cells[b][a].visited = true visited = visited + 1 end end end m = Maze.new(70,55) for i = 1,m.rows do for j = 1,m.cols do m:setVisitable(i, j, false) end end -- tree tree_data = {1,1,1,3,3,3,5,5,7,7,9,11,11,13,15,17,19,23,27,21, 13,15,17,17,19,21,23,27,29,33,25, 19,21,21,23,25,27,29,33,35,39,31,25, 23,25,27,29,31,33,35,37,41,45,37,31,21} for i, x in ipairs(tree_data) do for j = 1, x do m:setVisitable(m.rows-i-5, floor((m.cols - x) / 2) + j, true) m:setMeta(m.rows-i-5, floor((m.cols - x) / 2) + j, 'green') end end -- decorations c = floor(m.cols/2) colors = {'red', 'orange', 'purple'} ncolors = 3 for q = 0,3 do for j = c-15, c+15 do if j < c then k = 3 else k = 1.625 end for r = -1,1 do m:setMeta(floor((j - c) / k) + 15 + q * 10 + r, j, colors[math.random(ncolors)]) end end end -- star star_data = {1,1,1,3,3,5,9,15,9,5,3,3,1,1,1} for i, x in ipairs(star_data) do for j = 1, x do m:setVisitable(m.rows-i+1, floor((m.cols - x) / 2) + j, true) m:setMeta(m.rows-i+1, floor((m.cols - x) / 2) + j, 'yellow') end end -- trunk trunk_data = {7,7,9,11} for i, x in ipairs(trunk_data) do for j = 1, x do m:setVisitable(m.rows-i-61, floor((m.cols - x) / 2) + j, true) m:setMeta(m.rows-i-61, floor((m.cols - x) / 2) + j, 'brown') end end -- snow for i = 1,5 do for j = 1, m.cols do m:setVisitable(i,j, true) m:setMeta(i,j, 'white') end end m:create({x=1, y=1}) m.cells[1][1].west = false m.cells[m.rows][ceil(m.cols/2)].north = false \end{luacode*} \tikzset{ crayon/.style={line width=0.1cm, line cap=round, draw=#1}, crayon/.default=none, sketch/.style={bend right, out=rand*10, in=180-rand*10} } \def\luaprint#1{\directlua{tex.print(#1)}} \def\ifluacondition#1#2#3{% \def\nexta{#2}\def\nextb{#3}% \csname if\directlua{tex.print(tostring(#1))}\endcsname% \let\next=\nexta% \else% \let\next=\nextb% \fi% \next% } \begin{document} \begin{tikzpicture}[show background rectangle, background rectangle/.style={fill=black!85}, >=stealth] \foreach \i in {1,...,\luaprint{m.rows}}{ \foreach \j in {1,...,\luaprint{m.cols}}{ % \tikzset{shift={(\j,\i)}} \edef\currentcolor{\luaprint{m:getMeta(\i,\j)}} \ifluacondition{m:isVisitable(\i,\j)}{ \begin{pgfonlayer}{before-background} \filldraw [\currentcolor!5!black] (0,0) rectangle (1,1); \end{pgfonlayer} }{ \pgfmathparse{int(random(1,10))} \ifnum\pgfmathresult=1 \shade [top color=white, bottom color=gray] (0.5+rand/4,0.5+rand/4) circle [radius=.125]; \fi } \ifluacondition{m.cells[\i][\j].north and not m:isVisitable(\i+1,\j)}{ \begin{pgfonlayer}{foreground} \shade [top color=white, bottom color=gray] (0,0.9) to [sketch] ++(1,0) arc (-90:90:.15) to [sketch] ++(-1,0) arc (90:270:.15); \end{pgfonlayer} }{} \ifluacondition{m.cells[\i][\j].south} {\draw [crayon=\currentcolor] (0,0) to [sketch] (1,0);}{} \ifluacondition{m.cells[\i][\j].west and not m:isVisitable(\i,\j-1)} {\draw [crayon=\currentcolor] (0,0) to [sketch] (0,1);}{} \ifluacondition{m.cells[\i][\j].east}% {\draw [crayon=\currentcolor] (1,0) to [sketch] (1,1);}{} }} \draw [crayon=red, line width=0.25cm, ->] (0,1.5) -- ++(1.5,0); \draw [crayon=red, line width=0.25cm, ->] (\luaprint{ceil(m.cols/2)}+.5,\luaprint{m.rows}+.5) -- ++(0,1.5); \end{tikzpicture} \end{document} 

enter image description here

And here's an invisible tree from a couple of years ago.

\documentclass[border=0.125cm]{standalone} \usepackage{tikz} \pagecolor{black} \usetikzlibrary{shapes.geometric,decorations} \pgfmathdeclarerandomlist{colors}{{red}{yellow}{pink}{green}{orange}{purple}{blue}{white}} \newcommand\drawstar[1][]{% \pgfmathsetmacro\s{rnd*2+2} \pgfmathsetmacro\t{rnd*.5cm+0.5cm} \pgfmathsetmacro\y{rand*0.125cm} \pgfmathsetmacro\r{rand*180} \pgfmathrandomitem{\c}{colors} \node [star, fill=\c, star point ratio=\s, rotate=\r, minimum size=\t, inner sep=0pt, every star/.try, #1] at (0cm,\y pt) {}; } \pgfdeclaredecoration{stars}{start}{ \state{start}[width=rnd*.5cm+.25cm]{\drawstar} \state{final}{\drawstar} } \begin{document} \begin{tikzpicture}[line cap=round, x=1cm,y=1cm,] \draw [every star/.style={opacity=0.125}, decoration=stars, decorate] \foreach \i in {0,...,5}{ plot [domain=\i*360:\i*360+180, samples=100] (\x/300*cos \x, -\x/150+\x/900*sin \x) }; \draw [every star/.style={opacity=0.5}, decoration=stars, decorate] \foreach \i in {0,...,5}{ plot [domain=\i*360+180:\i*360+360, samples=100] (\x/300*cos \x, -\x/150+\x/900*sin \x) }; \drawstar[fill=yellow, minimum size=1.5cm] \end{tikzpicture} \end{document} 

enter image description here

And another:

\documentclass[tikz, border=0.25cm]{standalone} \usepackage{tikz} \pagecolor{black} \usetikzlibrary{decorations.pathreplacing} \makeatletter \newcount\tikzjointhedotsnumber \pgfdeclaredecoration{join the dots}{initial}{% \state{initial}[width=0pt, next state=do dots, persistent precomputation={\global\tikzjointhedotsnumber=1}]{} % \state{do dots}[width=\pgfdecoratedinputsegmentlength, persistent postcomputation={\global\advance\tikzjointhedotsnumber by1}]{% \pgfcoordinate{@dot-\the\tikzjointhedotsnumber}{\pgfpointorigin}% } % \state{final}{% % Is the last point the same as the first? \pgfpointdiff{\pgfpointdecoratedpathlast}{\pgfpointdecoratedpathfirst}% \pgfmathveclen{\the\pgf@x}{\the\pgf@y}% \ifdim\pgfmathresult pt=0pt\relax% \global\advance\tikzjointhedotsnumber by-1\relax \else \pgftransformshift{\pgfpointdecoratedpathlast}% \pgfcoordinate{@dot-\the\tikzjointhedotsnumber}{\pgfpointorigin}% \fi % Ok, now we do everything. Draw the dots and place the numbers. % \c@pgf@counta=\tikzjointhedotsnumber% \c@pgf@countb=2\relax% \edef\lastdot{\the\tikzjointhedotsnumber}% \def\nextdot{2}% \pgftransformreset% \pgfmathloop% \ifnum\pgfmathcounter>\tikzjointhedotsnumber \else% % Draw the dot. \edef\tmp{\the\tikzjointhedotsnumber}% \tikzjointhedotsnumber=\pgfmathcounter\relax% \path [shift={(@dot-\pgfmathcounter)}, every dot/.try, dot \pgfmathcounter/.try]; \tikzjointhedotsnumber=\tmp% % % Calculate the dot number node anchor \pgfmathanglebetweenpoints{\pgfpointanchor{@dot-\pgfmathcounter}{center}}{\pgfpointanchor{@dot-\the\c@pgf@counta}{center}}% \pgf@xc=\pgfmathresult pt\relax% \ifdim0pt>\pgf@xc% \advance\pgf@xc by360pt\relax% \fi% \pgfmathanglebetweenpoints{\pgfpointanchor{@dot-\pgfmathcounter}{center}}{\pgfpointanchor{@dot-\the\c@pgf@countb}{center}}% \pgf@yc=\pgfmathresult pt\relax% \ifdim0pt>\pgf@yc% \advance\pgf@yc by360pt\relax% \fi% \ifdim\pgf@xc>\pgf@yc% \pgf@x=360pt\relax% \else% \pgf@x=0pt\relax% \fi% \advance\pgf@x by-\pgf@xc% \advance\pgf@x by\pgf@yc% \divide\pgf@x by2\relax% \advance\pgf@x by\pgf@xc% \advance\pgf@x by180pt\relax% \edef\dotnumberanchor{\the\pgf@x}% \node [anchor=\dotnumberanchor, every dot number/.try, dot number \pgfmathcounter/.try] at (@dot-\pgfmathcounter) {\tikzjointhedotsnumber=\pgfmathcounter\relax\tikzjointhedotstypesetnumber{\tikzjointhedotsnumber}}; \c@pgf@counta=\pgfmathcounter\relax% \advance\c@pgf@countb by1\relax% \ifnum\c@pgf@countb>\tikzjointhedotsnumber% \c@pgf@countb=1\relax% \fi% \repeatpgfmathloop% } } % Command for typesetting dot number % #1 - a count register holding the current dot number % \def\tikzjointhedotstypesetnumber#1{\the#1} \makeatletter % Keys for setting dot number styles \tikzset{% syle dot number range/.code args={#1 to #2 with #3}{% \c@pgf@counta=#1 \pgfmathloop \ifnum\c@pgf@counta>#2\relax% \else% \tikzset{dot number \the\c@pgf@counta/.style={#3}}% \advance\c@pgf@counta by1 \repeatpgfmathloop% }, style dot number list/.code args={#1 with #2}{% \pgfutil@for\tmp:=#1\do{% \tikzset{dot number \tmp/.style={#2}}% }% } } \makeatother \tikzset{% % Executed for every dot every dot/.style={fill=white, insert path={ circle [radius=1mm] coordinate [alias=dot-last] (dot-\the\tikzjointhedotsnumber) } }, % Executed for every dot number every dot number/.style={ shape=circle, font=\sf, scale=2, text=white }, join the dots/.style={ decoration=join the dots, decorate }, lines/.style={ ultra thick, line join=round, line cap=round }, crayon/.style={ draw=#1, line join=round, line cap=round, line width=1mm }, sketch/.style={ bend right, out=rand*10, in=180-rand*10 } } \pgfdeclarelayer{background} \pgfsetlayers{background,main} \begin{document} \foreach \n in {1,...,40}{ \begin{tikzpicture}[line cap=round] \draw [decoration=join the dots, decorate,x=10cm,y=10cm, dot number 16/.style={anchor=south}, dot number 25/.style={anchor=south}, dot 1/.style={fill=black}, dot number 1/.append style={text=black, anchor=south east}, dot 40/.style={fill=black}, dot number 40/.append style={text=black, anchor=south west}] (0,0) \foreach \i in {1,...,3} { -- ++(-1/8,-1/3) -- ++(-1/4,-1/3) -- ++(-3/8,-1/3) -- ++(\i/6,0) -- ++(\i/6,1/16) } -- ++(1/8,0) -- ++(0,-1/4) -- ++(-1/2,0) -- ++(1/4,-1/2) -- ++(6/8,0) -- ++(1/4, 1/2) -- ++(-1/2,0) -- ++(0,1/4) -- ++(1/8,0) \foreach \i in {3,...,1} { -- ++(\i/6,-1/16) -- ++(\i/6,0) -- ++(-3/8,1/3) -- ++(-1/4,1/3) -- ++(-1/8,1/3) }; \begin{pgfonlayer}{background} \foreach \d in {4,9,14,27,32,37}{% \tikzset{shift=(dot-\d), yshift=1pt}% \pgfmathsetseed{99+\d*50}% % Candle \fill [lines, fill=purple!80, rounded corners=0.125cm] (-1/3,0) to [sketch] (-1/3,2) -- (1/3,2) to [sketch] (1/3,0); % Wick \draw [lines] (0,2) -- ++(0,1/4); \pgfmathsetseed{99+\n*50+\d*25}% \tikzset{shift={(0,2+1/8)}, xscale=round(rnd)*2-1,yscale=1+rand/8} \foreach \s/\c in {1/yellow,.5/red} \path [lines, fill=\c!50!orange, scale=\s] (0,0) arc (270:180:3/8) .. controls ++(0,1/4) and ++(0,-1/4) .. (0,3/2) arc (90:0:3/8 and 1) arc (360:270:3/8 and 1/2); } \path [fill=yellow!75!white, shift=(dot-1), rotate=22.5] (0:1.25) \foreach \i [evaluate={\j=mod(\i,2); \k=mod(\i+1,4)==0; \r=\j+1.25+\k+(\i==11);}] in {0,...,15}{ -- (\i*22.5:\r) } -- cycle; \end{pgfonlayer} \pgfmathsetseed{99} \draw [crayon=green!50!black, line width=1cm/8, sketch] (dot-1) \foreach \m in {1,...,\n}{ to [sketch] (dot-\m) }; \end{tikzpicture} } \end{document} 

enter image description here

Mark Wibrow
  • 71.6k
  • 4
  • 154
  • 208