ChevalierJoseph commited on
Commit
80069a5
·
verified ·
1 Parent(s): 78e86cd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +200 -94
app.py CHANGED
@@ -596,14 +596,14 @@ def generate(prompt, control_image, seed, random_seed, progress=gr.Progress(trac
596
 
597
  gallery = [(img1, "Uppercase"), (img2, "Lowercase"), (img3, "Punctuation")]
598
  preview = _render_preview(otf_path, font_name)
599
- status = f"<span class='dot'></span> <b>{font_name}</b> &nbsp;·&nbsp; seed <code>{seed}</code>"
600
  return gallery, preview, otf_path, status
601
 
602
 
603
  # =============================================================================
604
  # OPTIONAL CUSTOM TITLE FONT
605
  # Drop your own font in the repo as one of these names and the hero title will
606
- # use it (otherwise it falls back to Fraunces):
607
  # title.otf / title.ttf / title.woff2 / title.woff (or under assets/)
608
  # =============================================================================
609
  def _load_title_font():
@@ -626,136 +626,241 @@ def _load_title_font():
626
  f"src: url(data:{mime[ext]};base64,{b64}) format('{fmt[ext]}');"
627
  "font-weight: 100 900; font-style: normal; font-display: swap;}"
628
  )
629
- return face, "'TitleFont', 'Fraunces', Georgia, serif"
630
- return "", "'Fraunces', Georgia, serif"
631
 
632
  TITLE_FONT_FACE, TITLE_FAMILY = _load_title_font()
633
 
634
  # =============================================================================
635
- # THEME — type-foundry / specimen-sheet look (paper + ink + vermillion)
636
  # =============================================================================
637
  THEME = gr.themes.Base(
638
  primary_hue=gr.themes.colors.red,
639
- neutral_hue=gr.themes.colors.stone,
640
- font=[gr.themes.GoogleFont("Instrument Sans"), "ui-sans-serif", "sans-serif"],
 
641
  font_mono=[gr.themes.GoogleFont("JetBrains Mono"), "ui-monospace", "monospace"],
642
  ).set(
643
- body_background_fill="#EFE9DD",
644
- body_background_fill_dark="#EFE9DD",
645
- body_text_color="#1A1815",
646
- body_text_color_dark="#1A1815",
647
- body_text_color_subdued="#6E6A60",
648
- body_text_color_subdued_dark="#6E6A60",
649
- background_fill_primary="#FAF6EE",
650
- background_fill_primary_dark="#FAF6EE",
651
- background_fill_secondary="#F1EBDF",
652
- background_fill_secondary_dark="#F1EBDF",
653
- block_background_fill="#FAF6EE",
654
- block_background_fill_dark="#FAF6EE",
655
- block_border_color="#DAD3C4",
656
- block_border_color_dark="#DAD3C4",
657
  block_border_width="1px",
658
- block_label_text_color="#6E6A60",
659
- block_label_text_color_dark="#6E6A60",
660
- block_label_background_fill="#FAF6EE",
661
- block_label_background_fill_dark="#FAF6EE",
662
- block_title_text_color="#1A1815",
663
- block_title_text_color_dark="#1A1815",
664
- block_radius="3px",
 
 
665
  input_background_fill="#FFFFFF",
666
  input_background_fill_dark="#FFFFFF",
667
- input_border_color="#DAD3C4",
668
- input_border_color_dark="#DAD3C4",
669
- input_border_color_focus="#FF5128",
670
- input_border_color_focus_dark="#FF5128",
671
- button_primary_background_fill="#FF5128",
672
- button_primary_background_fill_dark="#FF5128",
673
- button_primary_background_fill_hover="#E8431F",
674
- button_primary_background_fill_hover_dark="#E8431F",
675
- button_primary_text_color="#FFF7F0",
676
- button_primary_text_color_dark="#FFF7F0",
677
- button_primary_border_color="#FF5128",
678
- button_primary_border_color_dark="#FF5128",
 
 
 
 
 
 
 
 
 
 
 
 
679
  )
680
 
681
  CSS = """
682
- @import url('https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,600;1,9..144,900&family=JetBrains+Mono:wght@400;600&display=swap');
 
 
 
 
 
 
 
 
 
 
683
 
684
  .gradio-container {
685
  max-width: 100% !important;
686
  width: 100% !important;
687
  margin: 0 !important;
688
- padding-left: clamp(16px, 4vw, 56px) !important;
689
- padding-right: clamp(16px, 4vw, 56px) !important;
690
- background:
691
- radial-gradient(1100px 520px at 92% -12%, rgba(255,81,40,0.10), transparent 60%),
692
- radial-gradient(820px 460px at -8% 112%, rgba(255,81,40,0.05), transparent 55%) !important;
 
 
 
 
 
 
 
693
  }
694
 
695
- /* Hero */
696
- #hero { padding: 10px 0 14px; border-bottom: 1px solid #DAD3C4; margin-bottom: 14px; }
697
- #hero .kicker {
698
- font-family: 'JetBrains Mono', monospace;
699
- text-transform: uppercase; letter-spacing: 0.34em;
700
- font-size: 10px; color: #FF5128; margin: 0 0 8px;
 
 
 
 
 
 
701
  }
702
  #hero h1 {
703
  font-family: __TITLE_FAMILY__;
704
- font-weight: 900; font-size: clamp(34px, 6vw, 64px);
705
- line-height: 0.9; letter-spacing: -0.03em; margin: 0; color: #1A1815;
 
 
 
 
706
  }
707
- #hero h1 em { font-style: italic; color: #FF5128; }
708
- #hero .tag {
709
- font-family: 'JetBrains Mono', monospace;
710
- font-size: 11px; line-height: 1.6; letter-spacing: 0.02em;
711
- color: #6E6A60; margin-top: 10px; max-width: 680px;
 
 
 
 
 
 
712
  }
713
- #hero .tag b { color: #1A1815; font-weight: 600; }
 
 
 
 
 
 
 
 
 
714
 
715
- /* Section eyebrow labels */
 
 
716
  .eyebrow {
717
- font-family: 'JetBrains Mono', monospace !important;
718
- text-transform: uppercase; letter-spacing: 0.22em;
719
- font-size: 10px !important; color: #9A9486 !important; margin: 4px 0 2px !important;
 
 
 
 
 
 
720
  }
 
721
 
722
- /* Component labels in mono */
723
  .gradio-container label span,
724
  .gradio-container .gr-check-radio label span {
725
- font-family: 'JetBrains Mono', monospace !important;
726
- letter-spacing: 0.06em; font-size: 11px !important; color: #6E6A60 !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
727
  }
728
 
729
- /* Primary CTA */
730
  .go-btn {
731
  text-transform: uppercase !important;
732
- letter-spacing: 0.16em !important;
733
- font-family: 'JetBrains Mono', monospace !important;
734
- font-weight: 600 !important;
735
  font-size: 12px !important;
736
- border-radius: 3px !important;
737
- min-height: 44px !important;
738
- box-shadow: 0 8px 22px -12px rgba(255,81,40,0.7) !important;
739
- transition: transform .12s ease, box-shadow .2s ease !important;
740
  }
741
- .go-btn:hover { transform: translateY(-1px); }
 
742
 
743
- /* Compaction — keep everything on one screen */
744
- #hero ~ .row, .gradio-container .gap { gap: 10px !important; }
745
  .gradio-container .padded, .gradio-container .block { padding: 10px !important; }
746
- .eyebrow { margin: 0 0 0 !important; }
747
 
748
  /* Status line */
749
  .status-line { min-height: 22px; }
750
  .status-line p {
751
- font-family: 'JetBrains Mono', monospace !important;
752
- font-size: 13px !important; color: #1A1815 !important; margin: 0 !important;
 
 
 
 
 
 
 
 
 
 
753
  }
754
- .status-line code { color: #FF5128; background: transparent; }
755
  .status-line .dot {
756
- display: inline-block; width: 8px; height: 8px; border-radius: 50%;
757
- background: #FF5128; margin-right: 8px;
758
- box-shadow: 0 0 10px rgba(255,81,40,0.6);
 
 
 
 
 
 
 
 
 
759
  }
760
 
761
  footer { display: none !important; }
@@ -768,19 +873,20 @@ with gr.Blocks(title="Typotopia", theme=THEME, css=CSS) as demo:
768
  gr.HTML(
769
  """
770
  <div id="hero">
771
- <p class="kicker">Generative type foundry</p>
772
- <h1>Typo<em>topia</em></h1>
773
- <p class="tag">
774
- From a single <b>prompt</b> or a <b>control image</b> to a complete OpenType file.
775
- FLUX.2-klein + custom LoRAs on <b>ZeroGPU</b> &rarr; potrace vectorization
776
- &rarr; fontTools assembly with pure-vector kerning.
777
- </p>
 
778
  </div>
779
  """
780
  )
781
  with gr.Row(equal_height=False):
782
  with gr.Column(scale=1):
783
- gr.HTML("<p class='eyebrow'>01 Brief</p>")
784
  prompt = gr.Textbox(
785
  label="Prompt",
786
  placeholder="e.g. a bold geometric sans inspired by brutalist concrete signage",
@@ -792,7 +898,7 @@ with gr.Blocks(title="Typotopia", theme=THEME, css=CSS) as demo:
792
  random_seed = gr.Checkbox(label="Random seed", value=True)
793
  btn = gr.Button("Generate font", variant="primary", elem_classes=["go-btn"])
794
  with gr.Column(scale=1):
795
- gr.HTML("<p class='eyebrow'>02 Specimen</p>")
796
  status = gr.HTML(elem_classes=["status-line"])
797
  otf_file = gr.File(label="Download .otf", height=80)
798
  preview = gr.Image(label="Preview", type="pil", height=160)
 
596
 
597
  gallery = [(img1, "Uppercase"), (img2, "Lowercase"), (img3, "Punctuation")]
598
  preview = _render_preview(otf_path, font_name)
599
+ status = f"<span class='dot'></span> <b>{font_name}</b><span class='sep'>/</span>seed <code>{seed}</code>"
600
  return gallery, preview, otf_path, status
601
 
602
 
603
  # =============================================================================
604
  # OPTIONAL CUSTOM TITLE FONT
605
  # Drop your own font in the repo as one of these names and the hero title will
606
+ # use it (otherwise it falls back to the Helvetica/Archivo grotesque stack):
607
  # title.otf / title.ttf / title.woff2 / title.woff (or under assets/)
608
  # =============================================================================
609
  def _load_title_font():
 
626
  f"src: url(data:{mime[ext]};base64,{b64}) format('{fmt[ext]}');"
627
  "font-weight: 100 900; font-style: normal; font-display: swap;}"
628
  )
629
+ return face, "'TitleFont', 'Helvetica Neue', Helvetica, 'Archivo', Arial, sans-serif"
630
+ return "", "'Helvetica Neue', Helvetica, 'Archivo', Arial, sans-serif"
631
 
632
  TITLE_FONT_FACE, TITLE_FAMILY = _load_title_font()
633
 
634
  # =============================================================================
635
+ # THEME — International Typographic Style (white / black / Swiss red)
636
  # =============================================================================
637
  THEME = gr.themes.Base(
638
  primary_hue=gr.themes.colors.red,
639
+ neutral_hue=gr.themes.colors.gray,
640
+ radius_size=gr.themes.sizes.radius_none,
641
+ font=["Helvetica Neue", "Helvetica", gr.themes.GoogleFont("Archivo"), "Arial", "sans-serif"],
642
  font_mono=[gr.themes.GoogleFont("JetBrains Mono"), "ui-monospace", "monospace"],
643
  ).set(
644
+ body_background_fill="#FFFFFF",
645
+ body_background_fill_dark="#FFFFFF",
646
+ body_text_color="#000000",
647
+ body_text_color_dark="#000000",
648
+ body_text_color_subdued="#6B6B6B",
649
+ body_text_color_subdued_dark="#6B6B6B",
650
+ background_fill_primary="#FFFFFF",
651
+ background_fill_primary_dark="#FFFFFF",
652
+ background_fill_secondary="#F4F4F4",
653
+ background_fill_secondary_dark="#F4F4F4",
654
+ block_background_fill="#FFFFFF",
655
+ block_background_fill_dark="#FFFFFF",
656
+ block_border_color="#D8D8D8",
657
+ block_border_color_dark="#D8D8D8",
658
  block_border_width="1px",
659
+ block_label_text_color="#000000",
660
+ block_label_text_color_dark="#000000",
661
+ block_label_background_fill="#FFFFFF",
662
+ block_label_background_fill_dark="#FFFFFF",
663
+ block_title_text_color="#000000",
664
+ block_title_text_color_dark="#000000",
665
+ block_radius="0px",
666
+ block_shadow="none",
667
+ block_shadow_dark="none",
668
  input_background_fill="#FFFFFF",
669
  input_background_fill_dark="#FFFFFF",
670
+ input_border_color="#000000",
671
+ input_border_color_dark="#000000",
672
+ input_border_color_focus="#E30613",
673
+ input_border_color_focus_dark="#E30613",
674
+ input_shadow="none",
675
+ input_shadow_dark="none",
676
+ input_shadow_focus="none",
677
+ input_shadow_focus_dark="none",
678
+ shadow_drop="none",
679
+ shadow_drop_lg="none",
680
+ button_primary_background_fill="#E30613",
681
+ button_primary_background_fill_dark="#E30613",
682
+ button_primary_background_fill_hover="#000000",
683
+ button_primary_background_fill_hover_dark="#000000",
684
+ button_primary_text_color="#FFFFFF",
685
+ button_primary_text_color_dark="#FFFFFF",
686
+ button_primary_border_color="#E30613",
687
+ button_primary_border_color_dark="#E30613",
688
+ button_secondary_background_fill="#FFFFFF",
689
+ button_secondary_background_fill_dark="#FFFFFF",
690
+ button_secondary_text_color="#000000",
691
+ button_secondary_text_color_dark="#000000",
692
+ button_secondary_border_color="#000000",
693
+ button_secondary_border_color_dark="#000000",
694
  )
695
 
696
  CSS = """
697
+ @import url('https://fonts.googleapis.com/css2?family=Archivo:wght@400;500;700;800&family=JetBrains+Mono:wght@400;500&display=swap');
698
+
699
+ :root {
700
+ --ink: #000000;
701
+ --paper: #FFFFFF;
702
+ --red: #E30613;
703
+ --grey: #6B6B6B;
704
+ --hairline: #D8D8D8;
705
+ --grotesk: 'Helvetica Neue', Helvetica, 'Archivo', Arial, sans-serif;
706
+ --mono: 'JetBrains Mono', ui-monospace, monospace;
707
+ }
708
 
709
  .gradio-container {
710
  max-width: 100% !important;
711
  width: 100% !important;
712
  margin: 0 !important;
713
+ padding-left: clamp(20px, 5vw, 72px) !important;
714
+ padding-right: clamp(20px, 5vw, 72px) !important;
715
+ background: var(--paper) !important;
716
+ }
717
+
718
+ /* Kill every radius and shadow — flat ink on paper */
719
+ .gradio-container *,
720
+ .gradio-container *::before,
721
+ .gradio-container *::after {
722
+ border-radius: 0 !important;
723
+ box-shadow: none !important;
724
+ text-shadow: none !important;
725
  }
726
 
727
+ /* =========================================================================
728
+ MASTHEAD wordmark left, tabular meta right, heavy rule below
729
+ ========================================================================= */
730
+ #hero { padding: 22px 0 0; margin-bottom: 18px; }
731
+ #hero .masthead {
732
+ display: flex;
733
+ justify-content: space-between;
734
+ align-items: flex-end;
735
+ gap: 32px;
736
+ flex-wrap: wrap;
737
+ border-bottom: 4px solid var(--ink);
738
+ padding-bottom: 18px;
739
  }
740
  #hero h1 {
741
  font-family: __TITLE_FAMILY__;
742
+ font-weight: 700;
743
+ font-size: clamp(44px, 8.5vw, 108px);
744
+ line-height: 0.82;
745
+ letter-spacing: -0.05em;
746
+ margin: 0;
747
+ color: var(--ink);
748
  }
749
+ #hero h1 .stop { color: var(--red); }
750
+ #hero .meta {
751
+ font-family: var(--grotesk);
752
+ font-size: 11px;
753
+ font-weight: 500;
754
+ text-transform: uppercase;
755
+ letter-spacing: 0.14em;
756
+ line-height: 1;
757
+ color: var(--ink);
758
+ min-width: 280px;
759
+ flex: 0 1 340px;
760
  }
761
+ #hero .meta .row {
762
+ display: flex;
763
+ justify-content: space-between;
764
+ gap: 24px;
765
+ padding: 7px 0;
766
+ border-top: 1px solid var(--ink);
767
+ }
768
+ #hero .meta .row:first-child { border-top: none; }
769
+ #hero .meta .k { color: var(--grey); }
770
+ #hero .meta .v { text-align: right; }
771
 
772
+ /* =========================================================================
773
+ SECTION HEADS — red index, black rule
774
+ ========================================================================= */
775
  .eyebrow {
776
+ font-family: var(--grotesk) !important;
777
+ text-transform: uppercase;
778
+ letter-spacing: 0.18em;
779
+ font-size: 11px !important;
780
+ font-weight: 700 !important;
781
+ color: var(--ink) !important;
782
+ border-top: 2px solid var(--ink);
783
+ padding-top: 8px !important;
784
+ margin: 0 0 6px !important;
785
  }
786
+ .eyebrow .idx { color: var(--red); margin-right: 12px; }
787
 
788
+ /* Component labels */
789
  .gradio-container label span,
790
  .gradio-container .gr-check-radio label span {
791
+ font-family: var(--grotesk) !important;
792
+ text-transform: uppercase;
793
+ letter-spacing: 0.12em;
794
+ font-size: 10px !important;
795
+ font-weight: 500 !important;
796
+ color: var(--ink) !important;
797
+ }
798
+
799
+ /* Inputs: ink rules on paper */
800
+ .gradio-container textarea,
801
+ .gradio-container input[type='text'],
802
+ .gradio-container input[type='number'] {
803
+ font-family: var(--grotesk) !important;
804
+ font-size: 14px !important;
805
+ border: 1px solid var(--ink) !important;
806
+ background: var(--paper) !important;
807
+ }
808
+ .gradio-container textarea:focus,
809
+ .gradio-container input:focus {
810
+ border-color: var(--red) !important;
811
+ outline: 2px solid var(--red) !important;
812
+ outline-offset: -1px;
813
  }
814
 
815
+ /* Primary CTA — red plate, uppercase, no ornament */
816
  .go-btn {
817
  text-transform: uppercase !important;
818
+ letter-spacing: 0.22em !important;
819
+ font-family: var(--grotesk) !important;
820
+ font-weight: 700 !important;
821
  font-size: 12px !important;
822
+ min-height: 48px !important;
823
+ border: none !important;
824
+ transition: background-color .12s ease !important;
 
825
  }
826
+ .go-btn:hover { background: var(--ink) !important; }
827
+ .go-btn:focus-visible { outline: 2px solid var(--ink) !important; outline-offset: 2px; }
828
 
829
+ /* Compaction — single-screen fit */
830
+ #hero ~ .row, .gradio-container .gap { gap: 12px !important; }
831
  .gradio-container .padded, .gradio-container .block { padding: 10px !important; }
832
+ .gradio-container .block { border-color: var(--hairline) !important; }
833
 
834
  /* Status line */
835
  .status-line { min-height: 22px; }
836
  .status-line p {
837
+ font-family: var(--grotesk) !important;
838
+ font-size: 13px !important;
839
+ color: var(--ink) !important;
840
+ margin: 0 !important;
841
+ letter-spacing: 0.02em;
842
+ }
843
+ .status-line b { font-weight: 700; }
844
+ .status-line code {
845
+ font-family: var(--mono);
846
+ font-size: 12px;
847
+ color: var(--ink);
848
+ background: transparent;
849
  }
850
+ .status-line .sep { color: var(--grey); margin: 0 8px; }
851
  .status-line .dot {
852
+ display: inline-block;
853
+ width: 9px; height: 9px;
854
+ background: var(--red);
855
+ margin-right: 10px;
856
+ vertical-align: baseline;
857
+ }
858
+
859
+ /* Progress bar in red, flat */
860
+ .gradio-container .progress-bar { background: var(--red) !important; }
861
+
862
+ @media (prefers-reduced-motion: reduce) {
863
+ .gradio-container * { transition: none !important; animation: none !important; }
864
  }
865
 
866
  footer { display: none !important; }
 
873
  gr.HTML(
874
  """
875
  <div id="hero">
876
+ <div class="masthead">
877
+ <h1>Typotopia<span class="stop">.</span></h1>
878
+ <div class="meta">
879
+ <div class="row"><span class="k">Input</span><span class="v">Prompt / Control image</span></div>
880
+ <div class="row"><span class="k">Model</span><span class="v">FLUX.2-klein + LoRA</span></div>
881
+ <div class="row"><span class="k">Output</span><span class="v">OpenType · GPOS kerning</span></div>
882
+ </div>
883
+ </div>
884
  </div>
885
  """
886
  )
887
  with gr.Row(equal_height=False):
888
  with gr.Column(scale=1):
889
+ gr.HTML("<p class='eyebrow'><span class='idx'>01</span>Brief</p>")
890
  prompt = gr.Textbox(
891
  label="Prompt",
892
  placeholder="e.g. a bold geometric sans inspired by brutalist concrete signage",
 
898
  random_seed = gr.Checkbox(label="Random seed", value=True)
899
  btn = gr.Button("Generate font", variant="primary", elem_classes=["go-btn"])
900
  with gr.Column(scale=1):
901
+ gr.HTML("<p class='eyebrow'><span class='idx'>02</span>Specimen</p>")
902
  status = gr.HTML(elem_classes=["status-line"])
903
  otf_file = gr.File(label="Download .otf", height=80)
904
  preview = gr.Image(label="Preview", type="pil", height=160)