diff --git a/.gitignore b/.gitignore index a584aebb..85903261 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,8 @@ node_modules package-lock.json docs/src/changelog.md docs/src/contributing.md +*.png +*.ico +.DS_Store +!logo.png +!favicon.ico \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 412c5dc9..88215cea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## Unreleased +- Add logo and favicon to docs [#307](https://github.com/JuliaIO/Zarr.jl/pull/307) ## v0.10.1 - 2026-07-07 diff --git a/README.md b/README.md index f9015702..dade60fb 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,9 @@ -Zarr is a Julia package providing an implementation of chunked, compressed, N-dimensional arrays. [Zarr](https://zarr.readthedocs.io/en/stable/) is originally a Python package. In Zarr we aim to implement the [zarr spec](https://zarr.readthedocs.io/en/stable/spec/v2.html). + + +`Zarr.jl` is a Julia package providing an implementation of chunked, compressed, N-dimensional arrays. [Zarr](https://zarr.readthedocs.io/en/stable/) is originally a Python package. In `Zarr.jl` we aim to implement the [zarr spec](https://zarr-specs.readthedocs.io/en/latest/specs.html). ## Package status @@ -32,7 +34,7 @@ z2[1:10,1:10] ## Links - https://discourse.julialang.org/t/a-julia-compatible-alternative-to-zarr/11842 - https://github.com/zarr-developers/zarr/issues/284 -- https://zarr.readthedocs.io/en/stable/spec/v2.html +- https://zarr-specs.readthedocs.io/en/latest/specs.html [docs-stable-img]: https://img.shields.io/badge/documentation-stable%20release-blue?style=round-square [docs-stable-url]: https://juliaio.github.io/Zarr.jl/stable/ diff --git a/docs/logo/Project.toml b/docs/logo/Project.toml new file mode 100644 index 00000000..a2e6db8c --- /dev/null +++ b/docs/logo/Project.toml @@ -0,0 +1,6 @@ +[deps] +CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" +Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" +GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a" +GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" diff --git a/docs/logo/logo.jl b/docs/logo/logo.jl new file mode 100644 index 00000000..31574406 --- /dev/null +++ b/docs/logo/logo.jl @@ -0,0 +1,201 @@ +using Colors +using GLMakie +using GeometryBasics +using Random +# using CairoMakie # don't use this one, the output comes with artifacts. GLMakie works fine. +# CairoMakie.activate!() + +function alpha_colorbuffer(scene) + bg = scene.backgroundcolor[] + scene.backgroundcolor[] = RGBAf(0, 0, 0, 1) + b1 = copy(Makie.colorbuffer(scene)) + scene.backgroundcolor[] = RGBAf(1, 1, 1, 1) + b2 = Makie.colorbuffer(scene) + scene.backgroundcolor[] = bg + return map(infer_alphacolor, b1, b2) +end +function infer_alphacolor(rgb1, rgb2) + rgb1 == rgb2 && return RGBAf(rgb1.r, rgb1.g, rgb1.b, 1) + c1 = Float64.((rgb1.r, rgb1.g, rgb1.b)) + c2 = Float64.((rgb2.r, rgb2.g, rgb2.b)) + alpha = @. 1 - (c1 - c2) * -1 # ( / (0 - 1)) + meanalpha = clamp(sum(alpha) / 3, 0, 1) + meanalpha == 0 && return RGBAf(0, 0, 0, 0) + c = @. clamp((c1 / meanalpha), 0, 1) + return RGBAf(c..., meanalpha) +end + +function make_logo(; is_wireframe::Bool = true, transparency::Bool = false, seed=16151, size = (600,600)) + Random.seed!(seed) + N = 7 + + left_points = [Point3f(0.5, j, k) for j in 1:N for k in 1:N] + back_points = [Point3f(i, 0.5, k) for i in 1:N for k in 1:N] + bottom_points = [Point3f(i, j, 0.5) for i in 1:N for j in 1:N] + + colors = ["#e58077", "#e34b75", "#bb1085", "#4063D8", "#389826", "#9558B2", "#00A3E0"] + + rot_angle = 3 * pi / 4 + tilt_angle = -pi / 8 # Tilt Z backwards by 22.5 degrees + global_rot = Makie.qrotation(Vec3f(0,0,1), Float32(rot_angle)) * Makie.qrotation(Vec3f(1,0,0), Float32(tilt_angle)) + + transform_p3(x_l, y_l, z_l) = begin + x_t = x_l + y_t = y_l * cos(tilt_angle) - (z_l - 4) * sin(tilt_angle) + z_t = y_l * sin(tilt_angle) + (z_l - 4) * cos(tilt_angle) + + x_rot = x_t * cos(rot_angle) - y_t * sin(rot_angle) + y_rot = x_t * sin(rot_angle) + y_t * cos(rot_angle) + + return Point3f(x_rot + 4, y_rot + 4, z_t + 4) + end + + z_pts_2d = [ + Point2f(-2.0, 6.4), # 1 + Point2f(2.0, 6.4), # 2 + Point2f(2.0, 5.434315), # 3 + Point2f(-1.034315, 2.4), # 4 + Point2f(2.0, 2.4), # 5 + Point2f(2.0, 1.6), # 6 + Point2f(-2.0, 1.6), # 7 + Point2f(-2.0, 2.565685), # 8 + Point2f(1.034315, 5.6), # 9 + Point2f(-2.0, 5.6) # 10 + ] + + z_vertices = Point3f[] + z_colors = Float32[] + for p in z_pts_2d + push!(z_vertices, transform_p3(p[1], -0.399, p[2])) + push!(z_colors, p[2]) + end + for p in z_pts_2d + push!(z_vertices, transform_p3(p[1], 0.399, p[2])) + push!(z_colors, p[2]) + end + + z_faces = GLTriangleFace[] + push!(z_faces, GLTriangleFace(1, 10, 9), GLTriangleFace(1, 9, 2), GLTriangleFace(2, 9, 3)) + push!(z_faces, GLTriangleFace(9, 8, 3), GLTriangleFace(8, 4, 3), GLTriangleFace(8, 7, 4)) + push!(z_faces, GLTriangleFace(4, 7, 6), GLTriangleFace(4, 6, 5)) + push!(z_faces, GLTriangleFace(11, 19, 20), GLTriangleFace(11, 12, 19), GLTriangleFace(12, 13, 19)) + push!(z_faces, GLTriangleFace(19, 13, 18), GLTriangleFace(18, 13, 14), GLTriangleFace(18, 14, 17)) + push!(z_faces, GLTriangleFace(14, 16, 17), GLTriangleFace(14, 15, 16)) + + boundary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1] + side_start = 20 + for i in 1:10 + u, v = boundary[i], boundary[i+1] + push!(z_vertices, z_vertices[u], z_vertices[v], z_vertices[v+10], z_vertices[u+10]) + push!(z_colors, z_colors[u], z_colors[v], z_colors[v+10], z_colors[u+10]) + idx = side_start + (i-1)*4 + push!(z_faces, GLTriangleFace(idx+1, idx+3, idx+2), GLTriangleFace(idx+1, idx+4, idx+3)) + end + fig = Figure(; size=size,) # backgroundcolor=:transparent + ax = LScene(fig[1,1]; show_axis=false,) + + cam = cameracontrols(ax.scene) + cam.eyeposition[] = Vec3f(14.008474063013997, 14.117945037759231, 9.072624070823204) + cam.lookat[] = Vec3f(4.25191593170166, 4.300845623016357, 3.3947386741638184) + cam.upvector[] = Vec3f(-0.26754081581622086, -0.269200937087842, 0.9251771939077157) + cam.fov[] = 45.0 + update_cam!(ax.scene, cam) + + set_ambient_light!(ax, RGBf(0.7, 0.7, 0.7)) + set_lights!(ax, [DirectionalLight(RGBf(0.15, 0.15, 0.15), cam.lookat[] - cam.eyeposition[])]) + + # Walls + wall_c1 = colorant"#2E3440" + wall_c2 = colorant"#E5E7EB" + left_colors = [rand((wall_c1, wall_c2)) for j in 1:N for k in 1:N] + back_colors = [rand((wall_c1, wall_c2)) for i in 1:N for k in 1:N] + bottom_colors = [rand((wall_c1, wall_c2)) for i in 1:N for j in 1:N] + + accent_colors = [colorant"#4063D8", colorant"#9558B2", colorant"#389826", colorant"#CB3C33"] + corner_indices = [1, N, (N-1)*N + 1, N^2] + for (i, idx) in enumerate(corner_indices) + if idx != 1 + left_colors[idx] = accent_colors[i] + back_colors[idx] = accent_colors[mod1(i+1, 4)] + bottom_colors[idx] = accent_colors[mod1(i+2, 4)] + end + end + + if is_wireframe + wall_alpha(p) = clamp(0.05f0 + 0.95f0 * max(0.0f0, (p[1] - 1.0f0)^2 + (p[2] - 1.0f0)^2 + (p[3] - 1.0f0)^2 - 0.25f0) / 72.0f0, 0.05f0, 1.0f0) + left_wf_marker = Rect3f(Vec3f(-0.025, -0.49, -0.49), Vec3f(0.05, 0.98, 0.98)) + left_solid_marker = Rect3f(Vec3f(-0.025, -0.49, -0.49), Vec3f(0.05, 0.98, 0.98)) + left_acc_pts = [p for (p, c) in zip(left_points, left_colors) if c in accent_colors] + left_acc_cls = [c for (p, c) in zip(left_points, left_colors) if c in accent_colors] + if !isempty(left_acc_pts) + meshscatter!(ax, left_acc_pts; marker=left_solid_marker, markersize=1f0, color=left_acc_cls, transparency=false, shading=true) + end + for (p, c) in zip(left_points, left_colors) + alpha_val = wall_alpha(p) + 0.1f0 + c_alpha = RGBAf(c.r, c.g, c.b, alpha_val) + wireframe!(ax, Rect3f(p .+ left_wf_marker.origin, left_wf_marker.widths); color=c_alpha, linewidth=1.5f0 * alpha_val, transparency=true) + end + + back_wf_marker = Rect3f(Vec3f(-0.49, -0.025, -0.49), Vec3f(0.98, 0.05, 0.98)) + back_solid_marker = Rect3f(Vec3f(-0.49, -0.025, -0.49), Vec3f(0.98, 0.05, 0.98)) + back_acc_pts = [p for (p, c) in zip(back_points, back_colors) if c in accent_colors] + back_acc_cls = [c for (p, c) in zip(back_points, back_colors) if c in accent_colors] + if !isempty(back_acc_pts) + meshscatter!(ax, back_acc_pts; marker=back_solid_marker, markersize=1f0, color=back_acc_cls, transparency=false, shading=true) + end + for (p, c) in zip(back_points, back_colors) + alpha_val = wall_alpha(p) + 0.1f0 + c_alpha = RGBAf(c.r, c.g, c.b, alpha_val) + wireframe!(ax, Rect3f(p .+ back_wf_marker.origin, back_wf_marker.widths); color=c_alpha, linewidth=1.5f0 * alpha_val, transparency=true) + end + + bot_wf_marker = Rect3f(Vec3f(-0.49, -0.49, -0.025), Vec3f(0.98, 0.98, 0.05)) + bot_solid_marker = Rect3f(Vec3f(-0.49, -0.49, -0.025), Vec3f(0.98, 0.98, 0.05)) + bot_acc_pts = [p for (p, c) in zip(bottom_points, bottom_colors) if c in accent_colors] + bot_acc_cls = [c for (p, c) in zip(bottom_points, bottom_colors) if c in accent_colors] + if !isempty(bot_acc_pts) + meshscatter!(ax, bot_acc_pts; marker=bot_solid_marker, markersize=1f0, color=bot_acc_cls, transparency=false, shading=true) + end + for (p, c) in zip(bottom_points, bottom_colors) + alpha_val = wall_alpha(p) + 0.1f0 + c_alpha = RGBAf(c.r, c.g, c.b, alpha_val) + wireframe!(ax, Rect3f(p .+ bot_wf_marker.origin, bot_wf_marker.widths); color=c_alpha, linewidth=1.5f0 * alpha_val, transparency=true) + end + else + meshscatter!(ax, left_points; marker=Rect3f(Vec3f(-0.1, -0.49, -0.49), Vec3f(0.2, 0.98, 0.98)), markersize=1f0, color=left_colors, transparency=transparency, shading=true) + meshscatter!(ax, back_points; marker=Rect3f(Vec3f(-0.49, -0.1, -0.49), Vec3f(0.98, 0.2, 0.98)), markersize=1f0, color=back_colors, transparency=transparency, shading=true) + meshscatter!(ax, bottom_points; marker=Rect3f(Vec3f(-0.49, -0.49, -0.1), Vec3f(0.98, 0.98, 0.2)), markersize=1f0, color=bottom_colors, transparency=transparency, shading=true) + end + + # Z shape + z_cmap = tuple.(reverse(colors[1:3]), 1) + z_mesh = GeometryBasics.normal_mesh(z_vertices, z_faces) + mesh!(ax, z_mesh; color=z_colors, colorrange=(2, 6), colormap=z_cmap, transparency=false, shading=true, shininess=128f0, specular=Vec3f(1.0, 1.0, 1.0)) + return fig, ax +end + +#wireframe +# with_theme(theme_dark()) do +fig, ax = make_logo(is_wireframe=true, transparency=true) +display(fig, update=false) +# end + +mkpath(joinpath(@__DIR__, "../src", "public")) +save(joinpath(@__DIR__, "../src", "public", "logo.png"), alpha_colorbuffer(fig.scene)) + +# favicon +fig_fav, ax_fav = make_logo(is_wireframe=true, transparency=true, size=(300,300)) +save(joinpath(@__DIR__, "../src", "public", "favicon.png"), alpha_colorbuffer(fig_fav.scene)) +mv(joinpath(@__DIR__, "../src", "public", "favicon.png"), joinpath(@__DIR__, "../src", "public", "favicon.ico"), force=true) + +# solid +fig_solid, ax_solid = make_logo(is_wireframe=false, transparency=false) +# display(fig, update=false) + +# mkpath(joinpath(@__DIR__, "../src", "public")) +save(joinpath(@__DIR__, "../src", "public", "logo_solid.png"), alpha_colorbuffer(fig_solid.scene)) + +# favicon solid +fig_fav_solid, ax_fav_solid = make_logo(is_wireframe=false, transparency=false, size=(300,300)) +save(joinpath(@__DIR__, "../src", "public", "favicon_solid.png"), alpha_colorbuffer(fig_fav_solid.scene)) +mv(joinpath(@__DIR__, "../src", "public", "favicon_solid.png"), joinpath(@__DIR__, "../src", "public", "favicon_solid.ico"), force=true) \ No newline at end of file diff --git a/docs/src/.vitepress/config.mts b/docs/src/.vitepress/config.mts index ef8d2536..89761cb2 100644 --- a/docs/src/.vitepress/config.mts +++ b/docs/src/.vitepress/config.mts @@ -153,7 +153,7 @@ export default defineConfig({ themeConfig: { outline: 'deep', - // logo: { src: '/logo_sq.png', width: 24, height: 24 }, + logo: { src: '/logo.png', width: 24, height: 24 }, search: { provider: 'local', options: { detailedView: true } diff --git a/docs/src/.vitepress/theme/style.css b/docs/src/.vitepress/theme/style.css index 898bfcb8..ef5b21d3 100644 --- a/docs/src/.vitepress/theme/style.css +++ b/docs/src/.vitepress/theme/style.css @@ -141,9 +141,9 @@ pre, code { --vp-home-hero-image-background-image: linear-gradient( -145deg, - #bb108582 30%, - #e3807799 30%, - #e34b75e3 + /* #bb108582 30%, */ + /* #e3807799 30%, */ + /* #e34b75e3 */ ); --vp-home-hero-image-filter: blur(40px); } @@ -158,9 +158,9 @@ pre, code { ); --vp-home-hero-image-background-image: linear-gradient( -45deg, - #c73562 30%, - #e58077, - var(--vp-dark-gray) 30% + /* #c73562 30%, */ + /* #e58077, */ + /* var(--vp-dark-gray) 30% */ ); --vp-home-hero-image-filter: blur(56px); } diff --git a/docs/src/index.md b/docs/src/index.md index a85c74de..6f3879e7 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -7,6 +7,9 @@ hero: name: "Zarr.jl" text: "A Julia library for the Zarr storage format" tagline: Chunked, compressed N-dimensional arrays for every scale and storage backend + image: + src: /logo.png + alt: Zarr.jl actions: - theme: brand text: Get Started diff --git a/docs/src/public/favicon.ico b/docs/src/public/favicon.ico new file mode 100644 index 00000000..463aa216 Binary files /dev/null and b/docs/src/public/favicon.ico differ diff --git a/docs/src/public/logo.png b/docs/src/public/logo.png new file mode 100644 index 00000000..6e3b6874 Binary files /dev/null and b/docs/src/public/logo.png differ